admin管理员组文章数量:1530085
这个问题是在我的个人网站项目上发生的,一直在寻找原因,排查了很多可能,都没有找到问题的所在,并困扰了我半年之多。后来由于无法解决,该问题便被搁置。最近由于网站将要做完,准备上线,便再次研究该问题,困扰半年的问题终于被解决。
以下(只贴出重点代码和配置):
框架: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
<aop:aspectj-autoproxy proxy-target-class="true"/>
<context:component-scan base-package="com.xiaohe66.web.**.service"/>
<context:component-scan base-package="com.xiaohe66.web.**.controller"/>
<context:component-scan base-package="com.xiaohe66.web.aop"/>
<context:component-scan base-package="com.xiaohe66.web.spring"/>
<!-- 开启注解 -->
<context:annotation-config/>
<!-- 导入配置 -->
<context:property-placeholder location="classpath:*.properties"/>
<bean id="springUtils" class="com.xiaohe66.webmon.util.SpringUtils"/>
<import resource="spring-mybatis.xml"/>
<import resource="spring-shrio.xml"/>
spring-mabatis.xml
<!-- 配置数据源 -->
<bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${datasource.driverClass}"/>
<property name="jdbcUrl" value="${datasource.url}"/>
<property name="user" value="${datasource.user}"/>
<property name="password" value="${datasource.password}"/>
</bean>
<!-- 开启注解事务 -->
<!--<tx:annotation-driven proxy-target-class="true" mode="aspectj"/>-->
<tx:annotation-driven proxy-target-class="true"/>
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<!-- 配置MyBaties全局配置文件:mybaconfnfig.xml -->
<property name="configLocation" value="classpath:mybatis/mybatis-config.xml" />
<!--
给包中的类注册别名,注册后可以直接使用类名
属性可以配置多个,可以用,;\t\n进行分割。但是不支持Ant风格的路径。如:com.xiaohe66.web.**.po
-->
<property name="typeAliasesPackage" value="com.xiaohe66.webm.po
com.xiaohe66.web.po
com.xiaohe66.web.security.po
com.xiaohe66.web.sys.po
com.xiaohe66.web.text.po
com.xiaohe66.web.home.po" />
<!-- 自动扫描mapper目录 -->
<property name="mapperLocations" value="classpath:com/xiaohe66/web/mapper/**/*.xml"/>
</bean>
<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg ref="sqlSessionFactory" />
</bean>
<!--自动扫描dao接口,并注入sqlsession-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.xiaohe66.web.**.dao"/>
<property name="sqlSessionTemplateBeanName" value="sqlSessionTemplate"/>
</bean>
spring-shrio.xml
<!-- 自定义Realm -->
<bean id="realmService" class="com.xiaohe66.web.security.RealmService"/>
<!-- 安全管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="realmService"/>
</bean>
<!-- 配置 Bean 后置处理器: 会自动的调用和 Spring 整合后各个组件的生命周期方法. -->
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
<!-- 开启shiro注解 -->
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<property name="securityManager" ref="securityManager"/>
</bean>
错误信息(重点部分):
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.开启了注解
<context:annotation-config/>
2.开启了aop,加上了proxy-target-class="true"
<aop:aspectj-autoproxy proxy-target-class="true"/>
3.开启了事务,加上了proxy-target-class="true"
<tx:annotation-driven proxy-target-class="true"/>
4.加入了cglib包(图片是maven打包后的war包)
结果发现,该有的配置都有,该加的包有加,百度谷歌都查吐了。愣是没有解决,而万恶的错误,还是一直存在。
--------------------------------------分割线--------------------------------------------
快要绝望的我,开始觉得会不会是spring的导入“<import resource="spring-mybatis.xml"/>”这种方式的问题。
于是我就将spirng-mybatis.xml里面的配置信息直接放到spring-context.xml中,并注释掉了导入的配置,如下
spring-context.xml:
<!--<import resource="spring-mybatis.xml"/>-->
<!--<import resource="spring-shrio.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/p/29161098,其中重点的一句话为:
bean被多次代理的时候,jdk代理是基于接口的,所以最后这个bean的类型变成了代理接口proxy的类型
然后,文章中也说明了问题的原因:
按文章所说的,我删除掉shrio中的该bean的配置后,项目果然能够成功启动。试了一下,事务管理有效。至此,困扰我半年多的问题终于被成功解决。
---------------------------------------------------------------------------------------
总结:
问题原因:bean的多次代理导致bean的类型变成了代理接口proxy的类型
解决:删除掉多余的代理,只保留一个
感想:很多事情,也许并不是表面的那样,要看清更深层次的原因。
参考:https://zhuanlan.zhihu/p/29161098
版权声明:本文标题:spring开启事务后报but was actually of type 'com.sun.proxy.$Proxy40异常 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://m.elefans.com/dianzi/1726602295a1077177.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论