Ich habe eine Spring-Webanwendung, die für die Verwendung von JDK-Proxys für AOP konfiguriert ist. Die AOP-Annotationen (z. B. @Transactional) werden auf den Schnittstellen und nicht in den Implementierungsklassen deklariert.AOP-Problem beim Ausführen von Spring Unit-Tests
Die Anwendung selbst funktioniert gut, aber wenn ich die Komponententests ausführen, scheint es versucht zu sein, CGLIB für die AOP-Funktionalität zu verwenden (anstelle von JDK-Proxy). Dies führt dazu, dass die Tests fehlschlagen. Ich habe die Stapelverfolgung unten angehängt.
Ich verstehe nicht, warum CGLIB verwendet wird, wenn ich die Tests ausführen, da die Spring-Konfiguration weitgehend identisch ist, als wenn die Anwendung ausgeführt wird. Ein möglicherweise signifikanter Unterschied besteht darin, dass die Testkonfiguration einen DataSourceTransactionManager anstelle eines JTA-Transaktionsmanagers verwendet. Die Testklassen selbst alle erweitern AbstractJUnit4SpringContextTests, könnte es sein, dass diese Klasse irgendwie fest verdrahtet ist, um CGLIB zu verwenden?
Caused by: org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class $Proxy25]: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Cannot subclass final class class $Proxy25
at org.springframework.aop.framework.Cglib2AopProxy.getProxy(Cglib2AopProxy.java:213)
at org.springframework.aop.framework.ProxyFactory.getProxy(ProxyFactory.java:110)
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.createProxy(AbstractAutoProxyCreator.java:488)
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.wrapIfNecessary(AbstractAutoProxyCreator.java:363)
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessAfterInitialization(AbstractAutoProxyCreator.java:324)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:361)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1343)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:473)
... 79 more
Caused by: java.lang.IllegalArgumentException: Cannot subclass final class class $Proxy25
at net.sf.cglib.proxy.Enhancer.generateClass(Enhancer.java:446)
at net.sf.cglib.transform.TransformingClassGenerator.generateClass(TransformingClassGenerator.java:33)
at net.sf.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)
at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:216)
at net.sf.cglib.proxy.Enhancer.createHelper(Enhancer.java:377)
at net.sf.cglib.proxy.Enhancer.create(Enhancer.java:285)
at org.springframework.aop.framework.Cglib2AopProxy.getProxy(Cglib2AopProxy.java:201)
... 86 more
EDIT: Einer der Kommentatoren gefordert, dass ich die Spring-Konfiguration posten. Ich habe es unten in abgekürzter Form eingefügt (d. H. Irrelevante Beans und XML-Namespaces wurden weggelassen).
feder servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<!-- ANNOTATION SUPPORT -->
<!-- Include basic annotation support -->
<context:annotation-config/>
<!-- CONTROLLERS -->
<!-- Controllers, force scanning -->
<context:component-scan base-package="com.onebigplanet.web.controller,com.onebigplanet.web.ws.*"/>
<!-- Post-processor for @Aspect annotated beans, which converts them into AOP advice -->
<bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator">
<property name="proxyTargetClass" value="true"/>
</bean>
<!-- An @Aspect bean that converts exceptions thrown in POJO service implementation classes to runtime exceptions -->
<bean id="permissionAdvisor" class="com.onebigplanet.web.advisor.PermissionAdvisor"/>
<bean id="businessIntelligenceAdvisor" class="com.onebigplanet.web.advisor.bi.BusinessIntelligenceAdvisor"/>
<!-- Finds the controllers and sets an interceptor on each one -->
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="interceptors">
<list>
<bean class="com.onebigplanet.web.interceptor.PortalInterceptor"/>
</list>
</property>
</bean>
<!-- METHOD HANDLER ADAPTER -->
<!-- Finds mapping of url through annotation on methods of Controller -->
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="cacheSeconds" value="0"/>
<property name="webBindingInitializer">
<bean class="com.onebigplanet.web.binder.WebBindingInitializer"/>
</property>
</bean>
</beans>
application-service.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<!-- Declares a bunch of bean post-processors -->
<context:annotation-config/>
<context:component-scan base-package="com.onebigplanet.service.impl,com.onebigplanet.dao.impl.mysql" annotation-config="false"/>
<!-- Property configurer -->
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="/WEB-INF/obp-service.properties" />
</bean>
<!-- Post-processor for @Aspect annotated beans, which converts them into AOP advice -->
<bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator"/>
<!-- An @Aspect bean that converts exceptions thrown in service implementation classes to runtime exceptions -->
<bean id="exceptionAdvisor" class="com.onebigplanet.service.advisor.ExceptionAdvisor"/>
<bean id="cachingAdvisor" class="com.onebigplanet.service.advisor.CacheAdvisor"/>
<bean id="businessIntelligenceAffiliateAdvisor" class="com.onebigplanet.service.advisor.BusinessIntelligenceAffiliateAdvisor"/>
<!-- Writable datasource -->
<jee:jndi-lookup id="dataSource" jndi-name="java:/ObpDS"/>
<!-- ReadOnly datasource -->
<jee:jndi-lookup id="readOnlyDataSource" jndi-name="java:/ObpReadOnlyDS"/>
<!-- Map the transaction manager to allow easy lookup of a UserTransaction -->
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>
<!-- Annotation driven transaction management -->
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
application-test.xml Dies wird nur aufgenommen, wenn die Einheit-Tests ausgeführt wird. Der Zweck besteht darin, einige der in den anderen Konfigurationsdateien deklarierten Beans zu überschreiben.
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<!-- Overwrite the property configurer bean such that it reads the test properties file instead -->
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="/obp-test.properties"/>
</bean>
<!-- All DAOs should use the test datasource -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${testDataSource.driverClassName}"/>
<property name="url" value="${testDataSource.url}"/>
<property name="username" value="${testDataSource.username}"/>
<property name="password" value="${testDataSource.password}"/>
</bean>
<bean id="readOnlyDataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${testDataSource.driverClassName}"/>
<property name="url" value="${testDataSource.url}"/>
<property name="username" value="${testDataSource.username}"/>
<property name="password" value="${testDataSource.password}"/>
</bean>
<!--
Overwrite the JTA transaction manager bean defined in applicationContent-service.xml with this one because
the implementation of the former is provided by JBoss
-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<beans>
Ich dachte, das könnte mehr aussehen mit "Java" und "Junit" Tags, also habe ich retagged. Ich wünschte, ich könnte mit der Antwort helfen! –
Hmm, interessant, ich laufe ein ähnliches Setup, das sehr ähnlich zu deinem ist, ohne Probleme. Können Sie Beispielcode (einschließlich Ihrer Kontext-XML-Dateien) posten? Haben Sie weitere Abhängigkeiten zu cglib? Kannst du es trotzdem versuchen, es aus dem Klassenpfad zu entfernen, nur um zu sehen, ob die Beans verdrahten? –