spring – 使用@Transactional时注入自动连接的依赖项失败

我测试我的DAO,但它没有用.发生以下错误:

Tests in error: 
  testAccountOperations(com.tsekhan.rssreader.dao.HibernateControllerTest): Error creating bean with name 'com.tsekhan.rssreader.dao.HibernateControllerTest': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.tsekhan.rssreader.dao.HibernateController com.tsekhan.rssreader.dao.HibernateControllerTest.hibernateController; nested exception is java.lang.IllegalArgumentException: Can not set com.tsekhan.rssreader.dao.HibernateController field com.tsekhan.rssreader.dao.HibernateControllerTest.hibernateController to $Proxy25

我的DAO:

@Service
@Scope("singleton")
public class HibernateController extends HibernateDaoSupport {

    @Autowired
    public SessionFactory sessionFactory;

    @Transactional
    public void addAcount(Account account) {
        sessionFactory.getCurrentSession().saveOrUpdate(account);
    }
}

我对这个DAO的测试:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:/applicationContext.xml")
public class HibernateControllerTest {

    @Autowired
    HibernateController hibernateController;

    private Set<Channel> getTestChannelList(String channelLink) {
        Channel testChannel = new Channel();
        testChannel.setSourceLink(channelLink);
        Set<Channel> testChannelList = new HashSet<Channel>();
        testChannelList.add(testChannel);
        return testChannelList;
    }

    private Account getTestAccount(String accountLogin, String channelLink) {
        Account testAccount = new Account();
        testAccount.setAccountLogin(accountLogin);
        testAccount.setChannelList(getTestChannelList(channelLink));
        return testAccount;
    }

    @Test
    public void testAccountOperations() {
        hibernateController
                .addAcount(getTestAccount("test_login", "test_link"));
    }
}

我的applicationContext.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.1.xsd"
        default-autowire="byName">

    <!-- Enabling spring-transaction annotations -->
    <tx:annotation-driven transaction-manager="transactionManager"/>

    <!-- Enabling annotation-driven configurating -->
    <context:annotation-config />

    <!-- Creation of transaction manager -->

    <bean id="transactionManager" scope="singleton" 
        class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>

    <bean id="sessionFactory" scope="singleton"
        class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
        <property name="configLocation" value="classpath:/hibernate.cfg.xml"/>
        <property name="configurationClass">
            <value>org.hibernate.cfg.AnnotationConfiguration</value>
        </property>
    </bean>
    <!--
    A Spring interceptor that takes care of Hibernate session lifecycle.
    -->
    <bean id="hibernateInterceptor" 
            class="org.springframework.orm.hibernate3.HibernateInterceptor">
        <property name="sessionFactory">
            <ref bean="sessionFactory"/>
        </property>
    </bean>

    <bean name="employeeDAO" scope="prototype" 
        class="com.tsekhan.rssreader.dao.HibernateController" />

    <!-- Searching for hibernate POJO files in package com.tsekhan.rssreader.web -->
    <context:component-scan base-package="com.tsekhan.rssreader.web" />
    <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />
    <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />

</beans>

我注意到,如果您在DAO中注释@Transactional,则会正确创建bean.怎么了?

首先,它真的很难将名称以Controller结尾给DAO而非常令人困惑,Controller和DAO都有不同的目的.

当你将@Transactional添加到服务或dao类时,为了使它在事务中工作需要创建该类的代理,它是一种包装器,它在执行代理类之前(考虑到代理的类) )方法spring启动事务,并且在执行之后如果没有异常完成事务,这可以在Spring中通过AOP和Annotations完成.在代码中描述.

public class OriginalDaoImpl implements OriginalDao extends DaoSupport {

  public void save(Object o){
      manager.save(o);
  }
}

public class ProxyDaoImpl implements OriginalDao {

    private OriginalDao originalDaoImpl; //instance of OriginalDaoImpl
    public void save(Object o){
       try{
            transaction.start();
            originalDaoImpl.save(o);
            transaction.commit(); 
       }catch(Exception e){
            transaction.rollback();
       }finally{
            //clean up code
       }
    }
}

如您所见,这不是一个确切的实现,而是一个基础代码,交易如何神奇地为您服务.关键点在于接口OriginalDao使得这种注入变得容易,因为OriginalDaoImpl和ProxyDaoImpl都实现了相同的接口.因此,它们可以被交换,即代理取代原件.可以通过Java动态代理在Java中创建此动态代理.现在,问题是如果你的类没有实现一个接口,那么更换就会变得更难.
据我所知,其中一个库CGLIB在这种情况下有所帮助,它为所考虑的类生成一个动态子类,并且在overriden方法中通过调用super.save(o)委托给它来执行魔术.原始代码.

现在来注射的问题.

>创建界面并使你的dao实现,并且spring将默认为JDK代理,因为它现在正在运行.
>将proxy-target-class =“true”属性添加到< tx:annotation-driven transaction-manager =“transactionManager”/>

就异常而言,它正在抛出,因为它期望注入的bean是’HibernateController’类型但不是.

有关您的参考,请参阅以下链接.

> 10.5.6 Using @Transactional
> Spring AOP Doc

希望这可以帮助 !!!!!.

相关文章
相关标签/搜索