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



我继承了一个使用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类,发现它们仍然具有相同的命名并包含相同的字段,因此基本上混淆没有对这两个类做任何事情。我拼命想弄明白Obfuscated是怎么破坏这个应用程序的,但是我很困惑。如果有人有任何想法,我很乐意听到你的意见。


(更新)我在下面添加我的图书馆的内容。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

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

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

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

最新更新