为什么Spring在混淆后看不到我的@Resource注解的对象?

问题描述 投票:0回答:2

我继承了一个使用 Spring 3.2 编写的应用程序。当应用程序在没有混淆的情况下构建时,它工作得绝对正常。一旦混淆(使用 ProGuard),我的日志中会出现以下异常。

 org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mailStoreFactoryImpl': Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [de.aeromaritime.messaging.roudistsrv.data.RdsDAO] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@javax.annotation.Resource(mappedName=, shareable=true, description=, name=, type=class java.lang.Object, lookup=, authenticationType=CONTAINER)}
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessPropertyValues(CommonAnnotationBeanPostProcessor.java:306)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1120)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:522)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:461)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:295)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:607)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:93)
at de.aeromaritime.messaging.roudistsrv.ServiceMain.main(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.rzo.yajsw.app.WrapperJVMMain.executeMain(WrapperJVMMain.java:53)
at org.rzo.yajsw.app.WrapperJVMMain.main(WrapperJVMMain.java:36)
 Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [de.aeromaritime.messaging.roudistsrv.data.RdsDAO] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@javax.annotation.Resource(mappedName=, shareable=true, description=, name=, type=class java.lang.Object, lookup=, authenticationType=CONTAINER)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:949)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:818)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:730)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.autowireResource(CommonAnnotationBeanPostProcessor.java:438)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.getResource(CommonAnnotationBeanPostProcessor.java:416)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor$ResourceElement.getResourceToInject(CommonAnnotationBeanPostProcessor.java:550)
at org.springframework.beans.factory.annotation.InjectionMetadata$InjectedElement.inject(InjectionMetadata.java:150)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessPropertyValues(CommonAnnotationBeanPostProcessor.java:303)
... 19 more  

问题是 RdsDAO 对象永远不会在 config.xml 中成为 bean。这意味着它必须由 Spring 的其他部分实例化。所以我环顾四周,发现

PersistenceExceptionTranslationPostProcessor
显然加载了用@Resource
@Repository
注释的对象。所以我检查了 RdsDAO 对象,果然它有正确的注释可供读取。

 @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.SERIALIZABLE, readOnly = true)
 @Repository
 public class RdsDAO implements Serializable
 { ...
 }

然后我查看了 config.xml 并发现

<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:aop="http://www.springframework.org/schema/aop"
   xmlns:context="http://www.springframework.org/schema/context"
   xmlns:jms="http://www.springframework.org/schema/jms"
   xmlns:lang="http://www.springframework.org/schema/lang"
   xmlns:tx="http://www.springframework.org/schema/tx"
   xmlns:util="http://www.springframework.org/schema/util"
   xmlns:p="http://www.springframework.org/schema/p"
   xmlns:amq="http://activemq.apache.org/schema/core"
   xmlns:ehcache="http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring"
   xmlns:task="http://www.springframework.org/schema/task"

   xsi:schemaLocation="
      http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
      http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
      http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
      http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms-3.0.xsd
      http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-3.xsd
      http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
      http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
      http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring/ehcache-spring-1.1.xsd
      http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd 

<!-- ### enable annotations -->
<context:annotation-config/>
<!-- ### scan for annotations -->
<context:component-scan base-package="de.aeromaritime.messaging.roudistsrv"/>
<!-- ### AOP support -->  
<!-- force use CGLIB to proxy classes even if there is an interface -->
<aop:aspectj-autoproxy proxy-target-class="true"/>

<context:spring-configured/>

<!-- Exception translation bean post processor -->
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>

<!-- ### Create the PlatformTransactionManager -->

<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="dataSource" ref="dataSource"/>
    <property name="entityManagerFactory" ref="entityManagerFactory"/>
    <property name="jpaDialect">
    <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
  </property>
</bean>

<!-- ### TX enable transaction annotations -->
<tx:annotation-driven transaction-manager="txManager"/>

因此

PersistenceExceptionTranslationPostProcessor
的 bean 已经存在并且应该可以工作(就像应用程序未混淆时一样)。

最后,我查看了

mailStoreFactoryImpl
bean 的代码,其中 RdsDAO 作为如下字段:

public final class MailStoreFactoryImpl extends UnicastRemoteObject implements
    ICMailStoreFactory, Serializable
{
    @Resource
    private RdsDAO rdsDAO;
  ...
}

最后只是为了检查,我反编译了 Jar 文件并查看了 RdsDAO 类和 MailStoreFactoryImpl 类,发现它们仍然具有相同的命名并包含相同的字段,因此基本上混淆没有对这两个类执行任何操作。我把头敲在桌子上,试图了解混淆是如何破坏这个应用程序的,但我不知所措。如果有人有任何想法,我很乐意听取您的意见。

[更新]
我在下面添加了我的library.pro 文件的内容:

#
# This ProGuard configuration file illustrates how to process a program
# library, such that it remains usable as a library.
# Usage:
#     java -jar proguard.jar @library.pro
#

# Specify the input jars, output jars, and library jars.
# In this case, the input jar is the program library that we want to process.

-injars      dist/ASYM_RDS-unobfuscated.jar
-outjars     dist/ASYM_RDS.jar

-libraryjars  <java.home>/lib/rt.jar
-libraryjars  dist/lib

# Save the obfuscation mapping to a file, so we can de-obfuscate any stack
# traces later on. Keep a fixed source file attribute and all line number
# tables to get line numbers in the stack traces.
# You can comment this out if you're not interested in stack traces.

-printmapping out.map
#-keepparameternames
#-renamesourcefileattribute SourceFile
#-keepattributes Exceptions,InnerClasses,Signature,Deprecated,
#                SourceFile,LineNumberTable,EnclosingMethod

# Preserve all annotations.

-keepattributes *Annotation*

# Preserve all public classes, and their public and protected fields and
# methods.

-keep public class * {
#    public protected *;
    public *;
}

# Preserve all .class method names.

-keepclassmembernames class * {
    java.lang.Class class$(java.lang.String);
    java.lang.Class class$(java.lang.String, boolean);
}

# Preserve all public applications.

-keepclasseswithmembers public class * {
    public static void main(java.lang.String[]);
}

# Preserve all native method names and the names of their classes.

-keepclasseswithmembernames class * {
    native <methods>;
}

# Preserve the special static methods that are required in all enumeration
# classes.

-keepclassmembers class * extends java.lang.Enum {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}

# Explicitly preserve all serialization members. The Serializable interface
# is only a marker interface, so it wouldn't save them.
# You can comment this out if your library doesn't use serialization.
# If your code contains serializable classes that have to be backward
# compatible, please refer to the manual.

-keepnames class * implements java.io.Serializable

-keepclassmembers class * implements java.io.Serializable {
    static final long serialVersionUID;
    private static final java.io.ObjectStreamField[] serialPersistentFields;
    !static !transient <fields>;
    private void writeObject(java.io.ObjectOutputStream);
    private void readObject(java.io.ObjectInputStream);
    java.lang.Object writeReplace();
    java.lang.Object readResolve();
}

#Added as per answer to SO question http://stackoverflow.com/posts/25419369
-keepclassmembers class * {
    @javax.annotation.Resource *;
}


# Your library may contain more items that need to be preserved; 
# typically classes that are dynamically created using Class.forName:

# -keep public class mypackage.MyClass
# -keep public interface mypackage.MyInterface
# -keep public class * implements mypackage.MyInterface

-ignorewarnings
-dontoptimize
java spring obfuscation
2个回答
0
投票

尝试将 -keepclassmembers 设置为@javax.annotation.Resource?

-keepclassmembers class * {
    @javax.annotation.Resource *;
}

如果这不起作用,您可能必须通过名称将上下文连接在一起,因为您的类名可能会被破坏。将 @Bean("somename") 添加到类中并将字段更新为 @Resource("somename") 以便它们匹配。


0
投票

你得到这个错误的解决方案了吗,我正在使用 spring 框架处理 java maven 项目,但我面临这个错误。

© www.soinside.com 2019 - 2024. All rights reserved.