spring开启事务后报but was actually of type 'com.sun.proxy.$Proxy40异常

这个问题是在我的个人网站项目上发生的,一直在寻找原因,排查了很多可能,都没有找到问题的所在,并困扰了我半年之多。后来由于无法解决,该问题便被搁置。最近由于网站将要做完,准备上线,便再次研究该问题,困扰半年的问题终于被解决。

以下(只贴出重点代码和配置):

框架: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开启事务后报but was actually of type 'com.sun.proxy.$Proxy40异常_第1张图片


结果发现,该有的配置都有,该加的包有加,百度谷歌都查吐了。愣是没有解决,而万恶的错误,还是一直存在。

--------------------------------------分割线--------------------------------------------

快要绝望的我,开始觉得会不会是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的类型

然后,文章中也说明了问题的原因:


spring开启事务后报but was actually of type 'com.sun.proxy.$Proxy40异常_第2张图片


按文章所说的,我删除掉shrio中的该bean的配置后,项目果然能够成功启动。试了一下,事务管理有效。至此,困扰我半年多的问题终于被成功解决。

---------------------------------------------------------------------------------------

总结:

问题原因:bean的多次代理导致bean的类型变成了代理接口proxy的类型

解决:删除掉多余的代理,只保留一个

感想:很多事情,也许并不是表面的那样,要看清更深层次的原因。


参考:https://zhuanlan.zhihu.com/p/29161098


你可能感兴趣的:(java)