2008-12-04 27 views
9

AOP için JDK proxy'lerini kullanacak şekilde yapılandırılmış bir Spring web uygulamasına sahibim. Uygulama sınıflarından ziyade, arayüzlerde AOP ek açıklamaları (@ Transactional gibi) belirtilir.AOP sorunu devam ediyor Yay birimi testleri

Uygulamanın kendisi iyi çalışıyor, ancak birim testlerini çalıştırdığımda, AOP işlevselliği için CGLIB'yi kullanmayı deniyor gibi görünüyor (JDK proxy'si yerine). Bu, sınamaların başarısız olmasına neden olur - aşağıdaki yığın izlemesini ekledim.

Testleri çalıştırırken neden CGLIB kullanıldığını anlamıyorum, çünkü Bahar yapılandırması büyük ölçüde uygulamanın çalıştığı zamankiyle aynıdır. Muhtemelen önemli bir fark, test konfigürasyonunun bir JTA işlem yöneticisi yerine bir DataSourceTransactionManager kullanmasıdır. Test sınıflarının hepsi, AbstractJUnit4SpringContextTests'u uzatıyorlar, bu sınıf bir şekilde CGLIB'yi kullanmak için zorlanmış olabilir mi?

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 

DÜZENLEME: yorumcularından biri Spring yapılandırmasını sonrası istedi. Aşağıda kısaltılmış biçimde (diğer bir deyişle ilgisiz çekirdekler ve XML ad alanları atlanmış) yer aldım.

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

yay servlet.xml 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 birim testler Bu yalnızca dahildir. Amacı, diğer yapılandırma dosyalarında bildirilen bazı çekirdeklerin üzerine yazmaktır.

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

Bu, "java" ve "junit" etiketleriyle daha fazla görüntü alabileceğini düşündüm, bu yüzden yeniden etiketlendim. Ben cevabın yardımıyla yardımcı olabilirdim! –

+0

Hmm, ilginç, ben sizinkiyle çok benzer bir benzer kurulum yapıyorum. Bazı örnek kod (içerik xml dosyaları dahil) gönderebilir misiniz? Ayrıca, cglib'de başka bağımlılıklarınız var mı? Öyle olsa bile, fasulye telinin olup olmadığını görmek için onu sınıf yolundan çıkarmayı deneyebilir misin? –

cevap

3

Hey Jean, CGLib proxy'leri proxy'lenecek sınıfı alt sınıflara ayırmak suretiyle oluşturulur - proxy'lerin kendileri son sınıflar olduklarından izin verilmeyen başka bir proxy'yi proxy yapmaya teşebbüs edersiniz. Dolayısıyla:

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

+0

Teşekkürler, ama bunun neden olduğu hakkında bir fikrin var mı? –

+0

Test etmek için önümde bir Spring uygulaması olmadan, kapsayıcıyı önyüklerken hem prod hem de test bağlamlarını eklediğinizden şüpheleniyorum. Tavsiyeyi kendi dosyasına dahil etmeyi deneyeceğim ve daha sonra her bir ürün ve test veri kaynağı ve tx-yöneticisi için bir dosya oluşturacağım. –

+0

Aynı fasulye kimliğinin birden çok örneğinde benzer bir sorun yaşadım. –

2

çözüm zaten paylaşılan ve ben de bunun bir yaşında bir sorgu olduğundan orijinal istekte, bir çözüm bulmuş olmalı eminim eğer bilmiyorum. Ancak kamu yararı için burada bahsetmeme izin verin. Bahar aşağıdaki beyan nedeniyle CGLIB kullanıyordu. CGLIB tetiklenen yerine JDK Dinamik Proxy olmamasının sağlanması amacıyla

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

mülkiyet

false olarak ayarlanmalıdır.

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

Yardım eder.