2008-12-04 11 views
9

मेरे पास एक स्प्रिंग वेब एप्लिकेशन है जो एओपी के लिए जेडीके प्रॉक्सीइंग का उपयोग करने के लिए कॉन्फ़िगर किया गया है। कार्यान्वयन कक्षाओं की बजाय इंटरऑस पर एओपी एनोटेशन (जैसे @ ट्रांसेक्शनल) घोषित किए जाते हैं।एओपी समस्या चल रही है स्प्रिंग यूनिट परीक्षण

एप्लिकेशन स्वयं ठीक काम करता है, लेकिन जब मैं यूनिट परीक्षण चलाता हूं, तो ऐसा लगता है कि एओपी कार्यक्षमता (जेडीके प्रॉक्सीइंग के बजाय) के लिए CGLIB का उपयोग करने का प्रयास किया जा रहा है। इससे परीक्षण विफल हो जाते हैं - मैंने नीचे स्टैक ट्रेस लगाया है।

मुझे समझ में नहीं आता कि परीक्षण चलाने पर CGLIB का उपयोग क्यों किया जा रहा है, क्योंकि स्प्रिंग कॉन्फ़िगरेशन काफी हद तक वही है जब एप्लिकेशन चल रहा है। एक संभावित रूप से महत्वपूर्ण अंतर यह है कि परीक्षण कॉन्फ़िगरेशन जेटीए लेनदेन प्रबंधक के बजाय 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 

संपादित करें: टिप्पणीकारों में से एक का अनुरोध मैं पोस्ट कि वसंत विन्यास। मैंने इसे संक्षेप में नीचे शामिल किया है (यानी अप्रासंगिक सेम और एक्सएमएल नेमस्पेस छोड़े गए हैं)।

वसंत-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

मैंने सोचा कि यह "जावा" और "जूनिट" टैग के साथ अधिक दिख सकता है, इसलिए मैंने पीछे हटना शुरू कर दिया। इच्छा है कि मैं जवाब के साथ मदद कर सकता हूँ! –

+0

हम्म, दिलचस्प, मैं आपकी तरह के समान सेटअप को बिना किसी समस्या के चलाता हूं। क्या आप कुछ नमूना कोड पोस्ट कर सकते हैं (आपके संदर्भ एक्सएमएल फाइलों सहित)? इसके अलावा, क्या आपके पास cglib पर अन्य निर्भरताएं हैं? फिर भी, क्या आप इसे देखने के लिए क्लासपाथ से इसे हटाने का प्रयास कर सकते हैं कि सेम तार? –

उत्तर

8

लगता है जैसे आप एक इंटरफ़ेस के बजाय कार्यान्वयन कक्षा का संदर्भ दे रहे हैं। अधिक जानकारी के साथ excerpt here है।

एक स्प्रिंग मंच पोस्ट: "Mixing JDK and CGLIB proxies"

एक महान ब्लॉग पोस्ट समझा pros and cons of JDK vs. CGLIB proxies

+0

लिंक के लिए धन्यवाद, मैं जांच करूँगा! –

3

हे जीन, सीजीएलआईबी प्रॉक्सी वर्ग को उप-वर्ग द्वारा उप-वर्ग द्वारा बनाया गया है - आप प्रॉक्सी को प्रॉक्सी करने का प्रयास कर रहे हैं, क्योंकि प्रॉक्सी स्वयं अंतिम कक्षाएं नहीं हैं। इसलिए:

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

+0

धन्यवाद, लेकिन कोई विचार क्यों यह हो रहा है? –

+0

परीक्षण के लिए मेरे सामने एक स्प्रिंग ऐप के बिना, मुझे इसकी संदेह है क्योंकि जब आप कंटेनर बूटस्ट्रैप करते हैं तो आप दोनों प्रोड और टेस्ट संदर्भों को शामिल करते हैं। मैं अपनी फाइल में सलाह को बाहरी करने की कोशिश करता हूं और फिर प्रत्येक प्रोड और टेस्ट डेटा स्रोतों और टीएक्स-प्रबंधकों के लिए एक फाइल बनाउंगा। –

+0

मुझे एक ही बीन आईडी के कई उदाहरणों के साथ एक ही समस्या है। –

2

मैं अगर समाधान पहले से ही साझा किया गया था और मैं भी यकीन है कि क्योंकि यह एक एक साल क्वेरी है मूल निवेदक, एक समाधान पाया है चाहिए हूँ पता नहीं है। सार्वजनिक हित के लिए हालांकि मुझे इसका जिक्र करने दें। निम्न घोषणा के कारण वसंत 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 गतिशील प्रॉक्सी ट्रिगर नहीं कर रहा है।

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

आशा है कि मदद करता है।