使用 @Transaction 注解与 @Autowired - Spring

10

我有一个带有@Service注解的类,与一些奇怪的问题相遇:当我在某个方法中放置@Transactional注解时,我无法启动Tomcat服务器,而在另一个类中使用@Autowired时,会出现错误:"无法自动装配...",但是当我移除@Transactional后,所有工作正常。

我的类头部如下:

@Service(value = "caixaBO")
public class CaixaBOImpl extends BasicBOImpl {

我的方法签名为:

@Transactional(propagation = Propagation.REQUIRED)
public void movimentarCaixaPaciente(String descricao, double valor,
        Paciente paciente) {

当我使用@Autowired CaixaBOImpl caixaBO时,由于@Transaction注释,在Tomcat初始化时出现错误。
编辑1:
1- 我在applicationContext.xml中有transactionManager,请看:
<!-- Configuracao do gerente de transacoes do Spring -->
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>

2 - 我的pom.xml文件中有CGLIB依赖,如下所示:

<dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib-nodep</artifactId>
            <version>2.2.2</version>
        </dependency>

编辑2

我的堆栈跟踪:

Grave: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'pedidoProteseBO': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private br.com.odontonew.financeiro.bo.CaixaBOImpl br.com.odontonew.odonto.bo.PedidoProteseBOImpl.caixaBO; nested exception is java.lang.IllegalArgumentException: Can not set br.com.odontonew.financeiro.bo.CaixaBOImpl field br.com.odontonew.odonto.bo.PedidoProteseBOImpl.caixaBO to com.sun.proxy.$Proxy36
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:288)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1074)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:517)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:293)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:290)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:192)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:585)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:895)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:425)
    at org.springframework.web.context.ContextLoader.createWebApplicationContext(ContextLoader.java:282)
    at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:204)
    at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:47)
    at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4701)
    at org.apache.catalina.core.StandardContext$1.call(StandardContext.java:5204)
    at org.apache.catalina.core.StandardContext$1.call(StandardContext.java:5199)
    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:724)
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private br.com.odontonew.financeiro.bo.CaixaBOImpl br.com.odontonew.odonto.bo.PedidoProteseBOImpl.caixaBO; nested exception is java.lang.IllegalArgumentException: Can not set br.com.odontonew.financeiro.bo.CaixaBOImpl field br.com.odontonew.odonto.bo.PedidoProteseBOImpl.caixaBO to com.sun.proxy.$Proxy36
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:508)
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:84)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:285)
    ... 20 more
Caused by: java.lang.IllegalArgumentException: Can not set br.com.odontonew.financeiro.bo.CaixaBOImpl field br.com.odontonew.odonto.bo.PedidoProteseBOImpl.caixaBO to com.sun.proxy.$Proxy36
    at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:164)
    at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:168)
    at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:81)
    at java.lang.reflect.Field.set(Field.java:741)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:504)
    ... 22 more
2个回答

6
我能想到两种可能导致这种情况:
  1. 您没有声明TransactionManager,因此无法应用@Transactional建议。
  2. 您的@Autowired目标声明为类型为CaixaBOImpl的字段,并且您的类路径上没有CGLIB库,因此Spring创建JDK代理而不是类代理。因此,它无法注入类型不匹配的代理。 您可以在此处获取CGLIB。或者您可以将@Autowired目标字段更改为类型BasicBOImpl。如果您在应用程序中注入其他类型为BasicBOImpl的bean而没有使用id进行限定,则会出现问题。
看起来即使您有CGLIB代理,Spring也会使用JDK代理。将tx:annotation-driven声明更改为:
<tx:annotation-driven proxy-target-class="true" /> 

所以,在我的帖子编辑中,我已经回答了你的两个问题。请阅读。 - Shelly
@user2776409,请发表您的异常堆栈跟踪和注入目标。 - Sotirios Delimanolis
我发布了我的堆栈跟踪。 - Shelly
很好,它能够工作。但是我不理解这个概念。JDK和Spring代理是什么,它们是如何工作的? - Shelly
@user2776409:请参考http://docs.spring.io/spring/docs/3.2.4.RELEASE/spring-framework-reference/html/aop.html#aop-introduction-proxies和http://docs.spring.io/spring/docs/3.2.4.RELEASE/spring-framework-reference/html/aop.html#aop-understanding-aop-proxies。 - JB Nizet
除了JB发布的推荐阅读材料外,您还应该熟悉JDK的Proxy类。Javadoc指出:代理类扩展java.lang.reflect.Proxy。因此,Spring尝试注入的对象类型是Proxy,而不是CaixaBOImpl,尽管它将是BasicBOImpl类型,因为它是一个接口。 - Sotirios Delimanolis

0
我们遇到了类似的问题,使用了一个“hack”的方法,似乎起作用了。只需让你的类实现一些接口即可。 这对我们起作用了-如果对你也有效,请告诉我。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接