Shiro入门遇到的一些问题

将Shiro整合进以前做的一个SSH的后台项目遇到了一些问题

Shiro组件与后台项目单独运行是正常的,结果结合之后后台项目无法启动,抛出了一个Failed to convert property value of type 'java.lang.String' to required type ' xxx.xxx.xxx' for property 'yyy.yyy.yyy'

排查很久发现是Shiro与service层上添加的Transaction注解存在一些问题,将Transaction注解去掉之后项目成功启动。

然而这并没有结束,项目虽然正常跑起来了,但是对后台功能进行测试的时候又抛出了一个异常:

org.springframework.dao.InvalidDataAccessApiUsageException: Write operations are not allowed in read-only mode (FlushMode.NEVER) - turn your Session into FlushMode.AUTO or remove 'readOnly' marker from transaction definition。

网上百度的原因主要有以下两个

原因一: 
这个异常产生的主要原因是DAO采用了Spring容器的事务管理策略,如果操作方法的名称和事务策略中指定的被管理的名称不能够匹配上,spring 就会采取默认的事务管理策略(PROPAGATION_REQUIRED,read only).如果是插入和修改操作,就不被允许的,所以包这个异常

原因二: 
在网上搜了一下,其中大多数文章又是提OpenSessionInViewFilter又是提OpenSessionInViewInterceptor的,大多云山雾罩、不知所云。(网上提到OpenSessionInViewFilter,因为缺省分配的Session是FlushMode.NEVER的。

其实这个异常的提示还是很明确的:在只读模式下(FlushMode.NEVER/MANUAL)写操作不被允许:把你的Session改成FlushMode.COMMIT/AUTO或者清除事务定义中的readOnly标记。

解决办法是在web.xml文件中,在struts过滤器配置前面加上

	<filter>
        <filter-name>OpenSessionInViewFilter</filter-name>
        <filter-class> org.springframework.orm.hibernate5.support.OpenSessionInViewFilter</filter-class>
        <init-param> 
           <param-name>flushMode</param-name> 
           <param-value>AUTO</param-value> 
       </init-param>
    </filter>
    
    <filter-mapping>
        <filter-name>OpenSessionInViewFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

然而这个问题后台项目早就将这个问题解决了,所以问题并不是出在hibernate上,继续上网百度Shiro与Spring整合出现的异常情况。

最终在切面编程(三):AspectJ与Shiro不兼容和Spring二次代理错误分析这篇文章中找到了这个问题的所在。

最终发现罪魁祸首是shiro配置中的DefaultAdvisorAutoProxyCreator会与Spring产生一个二次代理的问题,罪魁祸首是Shiro配置中的这个
  <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
        depends-on="lifecycleBeanPostProcessor" />

配置失效的原因:

  1. 由于使用了aop:aspectj-autoproxy强制了proxy-target-class
  2. 也就是说对Web层的Class(主要是Controller)使用了CGLib代理
  3. 然后在Shiro进行代理时使用DefaultAdvisorAutoProxyCreator
  4. 原本应该判断Controller,发现没有任何接口,所以使用CGLib来代理
  5. 但是由于Controller已经被CGLib代理过一次了
  6. DefaultAdvisorAutoProxyCreator拿到对不是Contoller本身,而是CGLib的代理结果
  7. CGLib的代理结果本身是有接口的,干扰了DefaultAdvisorAutoProxyCreator的内部判断
  8. 使用JDK去代理CGLib的代理结果
  9. 结果Controller的函数时去了CGLib的接口中找方法名,发现方法不存在,导致代理失败

解决办法:干掉DefaultAdvisorAutoProxyCreator

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值