这个问题是在我的个人网站项目上发生的,一直在寻找原因,排查了很多可能,都没有找到问题的所在,并困扰了我半年之多。后来由于无法解决,该问题便被搁置。最近由于网站将要做完,准备上线,便再次研究该问题,困扰半年的问题终于被解决。
以下(只贴出重点代码和配置):
框架:spring-4.3+springMVC-4.3+MyBatis+shrio+maven
JDK:1.8
服务器:tomcat8
数据库:MySql5.7
TestController:
@Controller
public class TestController {
@Autowired
private TestService testService;
@RequestMapping("/tx/test1")
@ResponseBody
public String test(){
return testService.test1();
}
}
TestService:
public class TestService {
@Autowired
private TestDao testDao;
@Transactional(rollbackFor = Exception.class)
public String test1(){
return "hello tx!";
}
}
spring-context.xml
spring-mabatis.xml
spring-shrio.xml
错误信息(重点部分):
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'testController':
Unsatisfied dependency expressed through field 'testService';
nested exception is org.springframework.beans.factory.BeanNotOfRequiredTypeException:
Bean named 'testService' is expected to be of type 'com.xiaohe66.web.security.service.TestService'
but was actually of type 'com.sun.proxy.$Proxy40'
---------------------------分割线----------------------------------------------------------
根据错误信息,我查阅了各方资料,知道了这个问题是由于动态代理使用了标准jdk的基于接口的代理方式。
而我的controller和service是没有实现任何接口的,因此我是需要使用基于类的代理方式的。
检查了自己的配置:
1.开启了注解
2.开启了aop,加上了proxy-target-class="true"
3.开启了事务,加上了proxy-target-class="true"
4.加入了cglib包(图片是maven打包后的war包)
结果发现,该有的配置都有,该加的包有加,百度谷歌都查吐了。愣是没有解决,而万恶的错误,还是一直存在。
--------------------------------------分割线--------------------------------------------
快要绝望的我,开始觉得会不会是spring的导入“
于是我就将spirng-mybatis.xml里面的配置信息直接放到spring-context.xml中,并注释掉了导入的配置,如下
spring-context.xml:
然后启动
Wath????启动了???????????没报错???????
访问一下
可以访问了,项目启动成功了。我开心的要跳起来了。但事情并没有想象中的那么简单。
--------------------------分割线--------------------------------------
项目启动成功后,测试了一下,事务成功的被应用了,抛出异常后,事务成功回滚。具体代码和过程就不说了。
然后,我再将spring-shrio.xml中的配置文件,也放到spring-context.xml中。启动
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'testController':
Unsatisfied dependency expressed through field 'testService';
nested exception is org.springframework.beans.factory.BeanNotOfRequiredTypeException:
Bean named 'testService' is expected to be of type 'com.xiaohe66.web.security.service.TestService'
but was actually of type 'com.sun.proxy.$Proxy40'
是的,我又看到了那段该死的错误。wath?什么情况?难道不是导入配置这种写法的问题?
然后我将spring-mybatis.xml中的配置还原,并删除掉spring-context.xml中的配置。然后注释掉spring-shrio.xml的相关配置。
启动。
结果是成功启动了。wath?是shrio的配置导致的问题?开始上网查找:shiro导致无法开启事务。
然后在知乎上看到这篇文章https://zhuanlan.zhihu.com/p/29161098,其中重点的一句话为:
bean被多次代理的时候,jdk代理是基于接口的,所以最后这个bean的类型变成了代理接口proxy的类型
然后,文章中也说明了问题的原因:
按文章所说的,我删除掉shrio中的该bean的配置后,项目果然能够成功启动。试了一下,事务管理有效。至此,困扰我半年多的问题终于被成功解决。
---------------------------------------------------------------------------------------
问题原因:bean的多次代理导致bean的类型变成了代理接口proxy的类型
解决:删除掉多余的代理,只保留一个
感想:很多事情,也许并不是表面的那样,要看清更深层次的原因。
参考:https://zhuanlan.zhihu.com/p/29161098