2008-12-04 6 views
9

У меня есть веб-приложение Spring, которое настроено на использование проксирования JDK для АОП. Аннотации AOP (такие как @Transactional) объявляются на интерфейсах, а не классах реализации.Проблема с АОП Пробег Весна модульные тесты

Приложение само по себе прекрасно работает, но когда я запускаю модульные тесты, похоже, пытается использовать CGLIB для функциональности AOP (вместо проксирования JDK). Это приводит к сбою тестов - я добавил трассировку стека ниже.

Я не понимаю, почему CGLIB используется, когда я запускаю тесты, потому что конфигурация Spring в основном такая же, как при запуске приложения. Одно из возможных различий заключается в том, что в тестовой конфигурации вместо диспетчера транзакций JTA используется DataSourceTransactionManager. Сами тестовые классы все распространяются на AbstractJUnit4SpringContextTests, может быть, этот класс как-то жестко связан с использованием CGLIB?

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: Один из комментаторов попросил меня опубликовать конфигурацию Spring. Я включил его ниже в сокращенном виде (т. Е. Неактуальные бобы и пространства имен XML опущены).

весна-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> 

ApplicationContext-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> 

ApplicationContext-test.xml Это включается только при выполнении модульных тестов. Цель состоит в том, чтобы перезаписать некоторые из компонентов, объявленных в других файлах конфигурации.

<?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> 
+0

Я думал, что это может получить больше взглядов с тегами «java» и «junit», поэтому я переделал. Хотел бы я помочь с ответом! – 2008-12-04 19:51:55

+0

Хм, интересно, я запускаю аналогичную установку, очень похожую на твою без проблем. Можете ли вы опубликовать некоторый пример кода (включая ваши xml-файлы контекста)? Кроме того, есть ли у вас другие зависимости от cglib? Тем не менее, можете ли вы попытаться удалить его из classpath просто, чтобы увидеть, если beans провод? – 2008-12-05 05:45:58

ответ

3

Hey Jean, прокси CGLib создаются путем подкласса класса, который должен быть проксированным - вы пытаетесь проксировать другой прокси-сервер, который не разрешен, поскольку прокси-серверы сами являются конечными классами. Следовательно:

Caused by: java.lang.IllegalArgumentException: Cannot subclass final class class $Proxy25

2

Я не знаю, если решение уже совместно, и я также уверен, что оригинальный запрашивающая должно быть найдено решение, так как это один год старый запрос. Однако для общественных интересов позвольте мне упомянуть об этом здесь. Spring использовала CGLIB из-за следующей декларации.

<!-- 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> 

Свойство должно быть установлено в ложь, так что CGLIB не запускается вместо JDK Dynamic проксирование.

<property name="proxyTargetClass" value="false"/> 

Надеюсь, что это поможет.