Spring 使用@Transactional时自动关联依赖项的注入失败
我正在测试我的刀,但它不起作用。出现以下错误:Spring 使用@Transactional时自动关联依赖项的注入失败,spring,hibernate,jakarta-ee,orm,annotations,Spring,Hibernate,Jakarta Ee,Orm,Annotations,我正在测试我的刀,但它不起作用。出现以下错误: 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
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"));
}
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(“类路径:/applicationContext.xml”)
公共类HibernateControllerTest{
@自动连线
HibernateController HibernateController;
私有集getTestChannelList(字符串channelLink){
通道测试通道=新通道();
testChannel.setSourceLink(channelLink);
Set testChannelList=newhashset();
testChannelList.add(testChannel);
返回testChannelList;
}
私有帐户getTestAccount(字符串accountLogin,字符串channelLink){
账户testAccount=新账户();
testAccount.setAccountLogin(accountLogin);
testAccount.setChannelList(getTestChannelList(channelLink));
返回测试帐户;
}
@试验
公开作废testAccountOperations(){
冬眠控制器
.addAcount(getestaccount(“test\u登录”、“test\u链接”);
}
}
My applicationContext.xml:
org.hibernate.cfg.AnnotationConfiguration
我注意到,如果您在DAO中注释@Transactional,则bean的创建是正确的。发生了什么事?首先,给一个DAO起个以Controller结尾的名字是很糟糕的。它非常令人困惑,Controller和DAO有着不同的用途 当您将
@Transactional
添加到服务或dao类中时,为了使spring在事务中工作,需要创建该类的代理,它是一种包装器,在执行代理类(考虑中的类是代理的)之前方法spring启动事务,在执行之后(如果没有异常完成事务),可以通过AOP和注释在spring中完成。用代码描述
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在这种情况下很有帮助,它为考虑中的类生成一个动态子类,在重写方法中,通过调用
super.save(o)
委托给原始代码来执行上述魔术
现在谈谈注射的问题
希望这有帮助 如果您使用的是
springmvc
,请确保在servlet上下文文件中单独扫描特定的控制器类。否则它将扫描2次,并且事务在应用程序上下文中不可用。BTW,IMHO对于DAO类,最好使用@Repository
注释,而不是@Service
。也许您应该澄清,在注入接口时,您不需要proxy target class=“true”
。另外,proxy target class=“true”
将中断接口上的@Transactional
。除此之外:+1.我的@Autowire不在接口上,但在类上。。。谢谢
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
}
}
}