今天碰到一个很sb的bug。
起因是:
@Controller public class DemoController { @Autowired private DemoService demoService; } @Service public class DemoService{ @Autowired private DemoRepository demoRespository; @Transactional public void addUser(UserInfo userInfo){ demoRespository.addUser(userInfo); } } //以上 run ok,然后我改为: @Controller public class DemoController { @Autowired private IDemoService demoService; } @Service public class DemoService implements IDemoService{ @Autowired private DemoRepository demoRespository; @Transactional public void addUser(UserInfo userInfo){ demoRespository.addUser(userInfo); } } //===总是报无法注入的bug, not such bean之类的。不应该啊! //===后来发现我个sb在另外一个controller中也用了DemoService,改为IDemoService就可以了 @Controller @RequestMapping(value="/user") public class UserController { @Autowired private DemoService demoService; }
在解决这个问题中,查找了一些相关资料,
DemoService无法注入的解释是:如果有Transactional,spring会生成一个proxy class, implements IDemoService,类似:
public class ProxyServiceImpl implements IDemoService { private DemoService demoService; //instance of OriginalDaoImpl public void addUser(Object o){ try{ transaction.start(); demoService.addUser(o); transaction.commit(); }catch(Exception e){ transaction.rollback(); }finally{ //clean up code } } }
所以注入必须是interface。
还有一种办法:
<tx:annotation-driven proxy-target-class="true" transaction-manager="transactionManager" /> //添加 proxy-target-class="true" 这样可以直接注入 @Controller public class DemoController { @Autowired private DemoService demoService; }
解释是:
<tx:annotation-driven/>
元素的 "proxy-target-class
" 属性值来控制是基于接口的还是基于类的代理被创建。
如果 "proxy-target-class
" 属值被设置为 "true
",那么基于类的代理将起作用(这时需要CGLIB库cglib.jar在CLASSPATH中)。如果 "proxy-target-class
" 属值被设置为 "false
" 或者这个属性被省略,那么标准的JDK基于接口的代理将起作用。
以上两种方法二选一,要不用第一种,不配置 "proxy-target-class"属性,代理基于接口,必须注入interface,
第二种:配置 "proxy-target-class" 属性 为true,代理基于类,注入class,