解決Spring JPA 使用@transaction註解時產生CGLIB代理沖突問題

Spring JPA 使用@transaction註解時產生CGLIB代理沖突

在使用JPA進行數據庫的刪除操作時需要使用@Transactional註解來支持事物:

 @Modifying
    @Transactional
    @Query(" delete from FollowerInfo " +
            " where crmAuth = :crmAuth and investUserId = :invUserId")
    void deleteByCrmAuthAndInvUserId(@Param("crmAuth") String crmAuth, @Param("invUserId") Long invUserId);

但是,在添加瞭如上方法後,測試服務啟動失敗。

查看日志報錯如下:

Caused by: java.lang.IllegalArgumentException: Cannot subclass final class class com.sun.proxy.$Proxy52
	at org.springframework.cglib.proxy.Enhancer.generateClass(Enhancer.java:446)
	at org.springframework.cglib.transform.TransformingClassGenerator.generateClass(TransformingClassGenerator.java:33)
	at org.springframework.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)
	at org.springframework.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:216)
	at org.springframework.cglib.proxy.Enhancer.createHelper(Enhancer.java:377)
	at org.springframework.cglib.proxy.Enhancer.createClass(Enhancer.java:317)
	at org.springframework.aop.framework.ObjenesisCglibAopProxy.createProxyClassAndInstance(ObjenesisCglibAopProxy.java:57)
	at org.springframework.aop.framework.CglibAopProxy.getProxy(CglibAopProxy.java:202)
	... 38 more
[2017-02-09 10:56:33 ERROR] [localhost-startStop-1] (org.springframework.web.context.ContextLoader:331) - Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'adviserCommFollowerServiceImpl': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.ounersc.ic.adviser.repository.community.AdviserCommFollowerRepository com.ounersc.ic.adviser.service.impl.AdviserCommFollowerServiceImpl.adviserCommFollowerRepository; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'adviserCommFollowerRepository': Post-processing of FactoryBean's singleton object failed; nested exception is org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class com.sun.proxy.$Proxy52]: 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 com.sun.proxy.$Proxy52
	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:334)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1204)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:538)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
	at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:229)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:725)
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:757)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:480)
	at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:403)
	at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:306)
	at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:106)
	at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4738)
	at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5181)
	at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
	at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1408)
	at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1398)
	at java.util.concurrent.FutureTask.run(FutureTask.java:262)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
	at java.lang.Thread.run(Thread.java:745)
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.ounersc.ic.adviser.repository.community.AdviserCommFollowerRepository com.ounersc.ic.adviser.service.impl.AdviserCommFollowerServiceImpl.adviserCommFollowerRepository; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'adviserCommFollowerRepository': Post-processing of FactoryBean's singleton object failed; nested exception is org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class com.sun.proxy.$Proxy52]: 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 com.sun.proxy.$Proxy52
	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:555)
	at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:331)
	... 22 more
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'adviserCommFollowerRepository': Post-processing of FactoryBean's singleton object failed; nested exception is org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class com.sun.proxy.$Proxy52]: 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 com.sun.proxy.$Proxy52
	at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.getObjectFromFactoryBean(FactoryBeanRegistrySupport.java:116)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getObjectForBeanInstance(AbstractBeanFactory.java:1512)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:313)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1081)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1006)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:904)
	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:527)
	... 24 more
Caused by: org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class com.sun.proxy.$Proxy52]: 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 com.sun.proxy.$Proxy52
	at org.springframework.aop.framework.CglibAopProxy.getProxy(CglibAopProxy.java:212)
	at org.springframework.aop.framework.ProxyFactory.getProxy(ProxyFactory.java:109)
	at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.createProxy(AbstractAutoProxyCreator.java:445)
	at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.wrapIfNecessary(AbstractAutoProxyCreator.java:331)
	at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessAfterInitialization(AbstractAutoProxyCreator.java:291)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:422)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.postProcessObjectFromFactoryBean(AbstractAutowireCapableBeanFactory.java:1713)
	at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.getObjectFromFactoryBean(FactoryBeanRegistrySupport.java:113)
	... 31 more
Caused by: java.lang.IllegalArgumentException: Cannot subclass final class class com.sun.proxy.$Proxy52
	at org.springframework.cglib.proxy.Enhancer.generateClass(Enhancer.java:446)
	at org.springframework.cglib.transform.TransformingClassGenerator.generateClass(TransformingClassGenerator.java:33)
	at org.springframework.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)
	at org.springframework.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:216)
	at org.springframework.cglib.proxy.Enhancer.createHelper(Enhancer.java:377)
	at org.springframework.cglib.proxy.Enhancer.createClass(Enhancer.java:317)
	at org.springframework.aop.framework.ObjenesisCglibAopProxy.createProxyClassAndInstance(ObjenesisCglibAopProxy.java:57)
	at org.springframework.aop.framework.CglibAopProxy.getProxy(CglibAopProxy.java:202)
	... 38 more
09-Feb-2017 10:56:33.145 SEVERE [localhost-startStop-1] org.apache.catalina.core.StandardContext.startInternal One or more listeners failed to start. Full details will be found in the appropriate container log file
09-Feb-2017 10:56:33.145 SEVERE [localhost-startStop-1] org.apache.catalina.core.StandardContext.startInternal Context [] startup failed due to previous errors

org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class com.sun.proxy.$Proxy52]: Common causes of this problem include using a final class or a non-visible class

對於此異常,這篇帖子中講到瞭產生該異常的原因,但是未給出解決辦法。

http://stackoverflow.com/questions/20063320/springmvc-proxy-issue

簡單來說,原因主要是代理沖突:Spring 早期的版本,要用com.sun.proxy的代理 ,而 jpa如果加瞭@transaction 註解後 需要用CGLIB的代理

因此產生瞭沖突

解決辦法:

Spring 已經在高版本中修復瞭該問題,把Spring從4.0升級到4.2.5後,問題解決:

在pom.xml加入:

   <properties>
        <spring.framework.version>4.2.5.RELEASE</spring.framework.version>
    </properties>

Spring 啟用CGLIB解決事物代理失敗

問題描述:

接口A提供公用的CRUD 操作,抽象類B實現接口A,接口C提供各模型特有的相關數據庫操作。

類D繼承抽象類B實現接口C如果使用JDK動態代理,Spring會將類D向上轉型為接口C,那麼在使用中必須註入接口A。

如果註入類D的類型。會報錯說代理類型XX無法轉換為類D的類型。

解決辦法如下:

<bean id="transactionManagerCMS"
  class="org.springframework.orm.hibernate4.HibernateTransactionManager">
  <property name="sessionFactory" ref="mySessionFactory" />
  <property name="dataSource" ref="dataSourceCMS" />
 </bean>
 <!-- the transactional advice (what 'happens'; see the <aop:advisor/> bean
  below) -->
 <tx:advice id="txAdvice" transaction-manager="transactionManagerCMS">
  <!-- the transactional semantics... -->
  <tx:attributes>
   <tx:method name="*" />
  </tx:attributes>
 </tx:advice>
 <!-- ensure that the above transactional advice runs for any execution of
  an operation defined by the FooService interface -->
 <aop:config proxy-target-class="true">
  <aop:pointcut id="fooServiceOperation"
   expression="execution(* com.harvest.smartHotels.info.dao.serviceContent.interfaces.*.*(..))" />
  <aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceOperation" />
 </aop:config>

動態代理使用CGLIB,這樣註入類型就可以使類D。

推薦閱讀: