我测试了我的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
我的道:
@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。会发生什么?
答案 0 :(得分:22)
首先,将控制器中的名称命名为DAO非常令人困惑,控制器和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在这种情况下有所帮助,它为所考虑的类生成一个动态子类,并且在override方法中通过调用super.save(o)
委托原始语法执行魔术。代码。
现在注射的问题。
proxy-target-class="true"
属性添加到<tx:annotation-driven transaction-manager="transactionManager"/>
就异常而言,它正在抛出,因为它期望注入的bean是'HibernateController'类型但不是。
如需参考,请参阅以下链接。
希望这有助于!!!!!。
答案 1 :(得分:0)
如果您正在使用Spring MVC
,请确保仅在servlet context file
中扫描特定的控制器类。否则,它将扫描2次,并且在应用程序上下文中无法进行事务处理。