Spring Data JPA 强制 CGLib 代理到非存储库类 [英] Spring Data JPA forces CGLib proxying to non repository classes

查看:31
本文介绍了Spring Data JPA 强制 CGLib 代理到非存储库类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将现有的 Spring 3 JPA 2 Hibernate Web 应用程序迁移到 Spring Data JPA.但是,只需将最新的 Spring Data JPA 添加到 Maven 项目并按以下方式配置 Spring Data

I am trying to migrate an existing Spring 3 JPA 2 Hibernate web application to Spring Data JPA. However just by adding the latest Spring Data JPA to the Maven project and configuring Spring Data as following

<jpa:repositories 
    base-package="myapp.persistence.spring" 
    entity-manager-factory-ref="entityManagerFactory"
    transaction-manager-ref="transactionManager" />

Spring 开始抱怨:

Spring starts complaining:

2012-07-31 16:54:23,153 ERROR [ContextLoader       ] - [Context initialization failed                                                                       ] - [remoteAddress=, remoteHost=, thread=pool-2-thread-1] org.springframework.web.context.ContextLoader
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'companyRepository' defined in file [C:DevelopmentApplicationServerapache-tomcat-7.0.27webappsmyappWEB-INFclassesmyapppersistenceCompanyRepository.class]: Initialization of bean failed; nested exception is org.springframework.aop.framework.AopConfigException: Cannot proxy target class because CGLIB2 is not available. Add CGLIB to the class path or specify proxy interfaces.
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:527) ~[spring-beans-3.1.2.RELEASE.jar:3.1.2.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456) ~[spring-beans-3.1.2.RELEASE.jar:3.1.2.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:294) ~[spring-beans-3.1.2.RELEASE.jar:3.1.2.RELEASE]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:225) ~[spring-beans-3.1.2.RELEASE.jar:3.1.2.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:291) ~[spring-beans-3.1.2.RELEASE.jar:3.1.2.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193) ~[spring-beans-3.1.2.RELEASE.jar:3.1.2.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:609) ~[spring-beans-3.1.2.RELEASE.jar:3.1.2.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918) ~[spring-context-3.1.2.RELEASE.jar:3.1.2.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:469) ~[spring-context-3.1.2.RELEASE.jar:3.1.2.RELEASE]
    at org.springframework.web.context.ContextLoader.createWebApplicationContext(ContextLoader.java:282) ~[spring-web-3.0.7.RELEASE.jar:3.0.7.RELEASE]
    at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:204) ~[spring-web-3.0.7.RELEASE.jar:3.0.7.RELEASE]
    at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:47) [spring-web-3.0.7.RELEASE.jar:3.0.7.RELEASE]
    at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4779) [catalina.jar:7.0.27]
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5273) [catalina.jar:7.0.27]
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) [catalina.jar:7.0.27]
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1566) [catalina.jar:7.0.27]
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1556) [catalina.jar:7.0.27]
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303) [na:1.6.0_24]
    at java.util.concurrent.FutureTask.run(FutureTask.java:138) [na:1.6.0_24]
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) [na:1.6.0_24]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) [na:1.6.0_24]
    at java.lang.Thread.run(Thread.java:662) [na:1.6.0_24]
Caused by: org.springframework.aop.framework.AopConfigException: Cannot proxy target class because CGLIB2 is not available. Add CGLIB to the class path or specify proxy interfaces.
    at org.springframework.aop.framework.DefaultAopProxyFactory.createAopProxy(DefaultAopProxyFactory.java:67) ~[spring-aop-3.1.2.RELEASE.jar:3.1.2.RELEASE]
    at org.springframework.aop.framework.ProxyCreatorSupport.createAopProxy(ProxyCreatorSupport.java:104) ~[spring-aop-3.1.2.RELEASE.jar:3.1.2.RELEASE]
    at org.springframework.aop.framework.ProxyFactory.getProxy(ProxyFactory.java:112) ~[spring-aop-3.1.2.RELEASE.jar:3.1.2.RELEASE]
    at org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor.postProcessAfterInitialization(PersistenceExceptionTranslationPostProcessor.java:133) ~[spring-tx-3.1.2.RELEASE.jar:3.1.2.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:407) ~[spring-beans-3.1.2.RELEASE.jar:3.1.2.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1461) ~[spring-beans-3.1.2.RELEASE.jar:3.1.2.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519) ~[spring-beans-3.1.2.RELEASE.jar:3.1.2.RELEASE]
    ... 21 common frames omitted

注意 Spring Data 被配置为扫描包 myapp.persistence.spring 而上面的错误引用了包 myapp.persistence 中的一个类.当我将 CGlib 添加到项目中时,包括 Spring Data 在内的一切都可以正常工作.但是发生了什么?我是春季菜鸟,很困惑.我无法弄清楚 Spring Data 是如何实现它的代理魔法的.至少官方的例子根本不包括CGlib.更多信息:

Notice that Spring Data is configured to scan package myapp.persistence.spring while the error above references a class from package myapp.persistence. When I add CGlib to the project everything including Spring Data works fine. But what's happening? I am a Spring rookie and quite puzzled. I could not figure out how Spring Data does it's proxy magic. At least the official examples do not include CGlib at all. Further information:

CompanyRepository 是一个简单的自制 JPA-DAO,使用 EntityManager:

CompanyRepository is a simple self-made JPA-DAO using EntityManager:

@Repository
@Transactional(propagation = Propagation.MANDATORY)
public class CompanyRepository extends AbstractRepository<Company, Long> {
  …
}

事务通过 @Transactional 和 AspectJ 编译时编织启用.上下文配置片段:

Transactions are enabled via @Transactional and AspectJ compile time weaving. Context configuration snippet:

<tx:annotation-driven proxy-target-class="true" mode="aspectj"/>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>

部署到Tomcat 7.0.27

Deployed to Tomcat 7.0.27

推荐答案

参考文档 使用 <jpa:repositories/> 激活用 注释的 Spring bean 的持久性异常翻译>@Repository.截至 JavaDoc@Repository 注释的主要目的是异常翻译,它将应用于用它注释的组件.如果您的类实现了一个接口,则可以使用普通的 JDK 代理.如果没有 - 就像你的情况一样 - 需要 CGLib 来创建代理.Spring 参考文档.

As described in the reference documentation using <jpa:repositories /> activates persistence exception translation for Spring beans annotated with @Repository. As of the JavaDoc of @Repository the primary purpose of the annotation is exception translation which will be applied to the component annotated with it. If your class implements an interface plain JDK proxies can be used. If it does not - as in your case - CGLib is required to create the proxy. More details on that in the Spring reference documentation.

要在不使用 CGLib 的情况下使用 ,您在场景中基本上有两种选择:

To use <jpa:repositories /> without CGLib you essentially have two choices in your scenario:

  1. 为每个用 @Repository 注释的组件引入一个接口.这仍将应用持久性异常转换,这可能是您想要的.
  2. 首先不要使用 @Repository,而是使用 @Component 基本上禁用这些组件的异常转换.
  1. Introduce an interface for each component annotated with @Repository. This will still apply the persistence exception translation which is probably what you want.
  2. Not use @Repository in the first place but rather @Component essentially disabling exception translation for these components.

这篇关于Spring Data JPA 强制 CGLib 代理到非存储库类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆