問題:
The bean 'xxx' could not be injected as a 'com.github.service.xx' because it is a JDK dynamic proxy
先說說問題的來源吧,當前這個問題是我在springboot配置事務時出現的,本來我搭建了一個springboot的web框架后,啟動事務配置只需要如下兩步即可完成:
1.在啟動類Application類上設置@EnableTransactionManagement,表示啟動springboot事務支持
2.在Service層的實現類中指定的方法上設置@Transactional
以上簡單的兩步即可完成,但偏偏在啟動后會報如上錯誤。通過觀察控制台報錯的原因如下:
Console描述1:
Description:
The bean 'userServiceImpl' could not be injected as a 'com.ysq.springboot.service.Impl.UserServiceImpl' because it is a JDK dynamic proxy that implements:
com.ysq.springboot.service.UserService
根據上面描述,它是在我的Action層中,注入userServiceImpl這個Bean時失敗,(失敗的原因就是我有實現接口,而springboot的事務默認是使用jdk的動態代理,即基於接口))。到這里我突然明白了,在action層中我注入的Bean是實現類,因此就會報錯。於是我將此注入Bean的方式改成了其接口,問題迎刃而解。
Console描述2:
Action:
Consider injecting the bean as one of its interfaces or forcing the use of CGLib-based proxies by setting proxyTargetClass=true on @EnableAsync and/or @EnableCaching.
在看上面的描述它給了我們解決此問題的方案,說你可以考慮下將action中注入的Bean改成接口方式或者強迫事務使用CGLib代理方式(基於類,即設置proxyTargetClass=True在啟動事務管理上@EnableTransactionManagement(proxyTargetClass=True)),這種以CGLib代理方式進行,按照之前寫法,我們應該是需要引入相應的cglib庫的jar包。而在springboot中已經集成了。但在spring3.2之前是需要引入的;
假如你是在不想將注入的Bean改成接口方式,非得要用實現類,而且還不想再啟動事務時配置proxyTargetClass=true,那么接下來讓你知道什么叫厲害,有如下方法:
在你Service層對應的實現類上配置@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)注解,表明此類上所有方法上的事務都是CGLib方式代理的,問題照樣可以解決。(參考:https://blog.csdn.net/z394642048/article/details/84759331)
寫在最后:這里我需要強調一點,就是網上有些解決此問題都說在properties文件中設置spring.aop.proxy-target-class=true。你要搞清楚我們的問題是在開啟springboot事務時出現的哦,雖然和AOP代理過程產生的問題一樣,但解決的方式不同額。
參考文獻:
https://github.com/alibaba/druid/issues/2330
https://blog.csdn.net/m0_38016299/article/details/78390363