Spring Data JPA强制CGLib代理到非存储库类 [英] Spring Data JPA forces CGLib proxying to non repository classes
问题描述
我正在尝试将现有的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" />
春天开始抱怨:
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:\Development\ApplicationServer\apache-tomcat-7.0.27\webapps\myapp\WEB-INF\classes\myapp\persistence\CompanyRepository.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
请注意,当上面的错误引用了软件包myapp.persistence
中的类时,Spring Data已配置为扫描软件包myapp.persistence.spring
.当我将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
是使用EntityManager的简单的自制JPA-DAO:
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
推荐答案
如 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的情况下使用<jpa:repositories />
,您在方案中实际上有两个选择:
To use <jpa:repositories />
without CGLib you essentially have two choices in your scenario:
- 为每个用
@Repository
注释的组件引入一个接口.这仍然会应用您可能想要的持久性异常转换. - 首先不使用
@Repository
,而实际上@Component
禁用这些组件的异常翻译.
- Introduce an interface for each component annotated with
@Repository
. This will still apply the persistence exception translation which is probably what you want. - Not use
@Repository
in the first place but rather@Component
essentially disabling exception translation for these components.
这篇关于Spring Data JPA强制CGLib代理到非存储库类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!