有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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

我继承了一个使用Spring3.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对象永远不会在配置中生成bean。xml。这意味着它必须由弹簧的其他部分实例化。所以我环顾四周,发现PersistenceExceptionTranslationPostProcessor显然加载了用@Resource@Repository注释的对象。所以我检查了RdsDAO对象,确定它有正确的注释可以读取

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

然后我查看了配置。xml和find

<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就在那里并且应该可以工作(当应用程序没有被混淆时也是如此)

最后,我查看了我的mailStoreFactoryImplbean的代码,它的RdsDAO字段如下:

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

最后,为了检查,我反编译了我的Jar文件,查看了RdsDAO类和MailStoreFactoryImpl类,发现它们仍然具有相同的命名和包含相同的字段,所以基本上混淆对这两个类都没有任何作用。我拼命想弄明白模糊处理程序是怎么破坏这个应用程序的,但我不知所措。如果有人有什么想法,我很想听听你的意见

[更新]
我在下面添加我的库的内容。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

共 (1) 个答案

  1. # 1 楼答案

    尝试将-keepclassmembers设置为@javax。注释。资源

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

    如果这不起作用,您可能必须按名称将上下文连接在一起,因为您的类名可能会被损坏。将@Bean(“somename”)添加到类中,并将字段更新为@Resource(“somename”),使其匹配