代理的坑,你入了没?

1、基本框架:spring+springMvc+shiro+mybatis

2、基本版本:

 

3、目标:搭建一个主要是在service层级不用接口的环境。

     Spring的注解是基于接口的,事务的代理对于自带的JDK代理而言也是基于接口的,所以如果不是基于接口代理的库,所有涉及代理的地方都要使用cglib库(cglib库的代理是基于类的,随便搜搜就知道了)。【好多坑,弄了好久!】

项目结构:(其实就是service层级不写接口)


Spring容器配置:(就是下面的几个xml)


其他配置不谈,说关键,service采用注解形式加事务,事务必定有代理,

一般的配置是:

<!-- 事务管理器 -->
    <bean id="mytransactionManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource"ref="dataSource"/>
    </bean>
    <!-- 启动注解事务 -->
<tx:annotation-driven transaction-manager="mytransactionManager"/>

   上面的bean 一般都是这样不会改变多大,但是tx:annotation-driven 启动注解事务的时候,事务的代理默认是基于接口的,正常情况下如果要是需要基于类的代理,只要加上proxy-target-class="true" 属性即可,即

<tx:annotation-driven  proxy-target-class="true"transaction-manager="mytransactionManager"/>

但是很遗憾,此配置无效,仍然会在启动时报错(错误处在初始化spring容器时,自定义的Realm里面的注入注解无法注入)

org.springframework.beans.factory.BeanCreationException:Error creating bean with name 'shiroFilter'
 defined in file[D:\zhonghai\eclspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\zhong\WEB-INF\classes\applicationContext-shiro.xml]:
   Cannot resolve reference to bean 'securityManager' while setting bean property'securityManager'; nested exception isorg.springframework.beans.factory
     .BeanCreationException: Error creating beanwith name 'securityManager' defined in file[D:\zhonghai\eclspace\.metadata\.plugins\org.eclipse
     .wst.server.core\tmp0\wtpwebapps\zhong\WEB-INF\classes\applicationContext-shiro.xml]:Cannot resolve reference to bean 'upmsRealm' 
  while setting bean property'realms' with key [0]; nested exception isorg.springframework.beans.factory.BeanCreationException:
  Error creating beanwith name 'upmsRealm': Injection of autowired dependencies failed;
  nestedexception is org.springframework.beans.factory.BeanCreationException: Could notautowire field:
 private com.zhong.upms.service.UpmsUserServicecom.zhong.upms.common.shiro.realm.UpmsRealm.upmsUserService;
   nested exceptionis java.lang.IllegalArgumentException: Can not setcom.zhong.upms.service.UpmsUserService 
   fieldcom.zhong.upms.common.shiro.realm.UpmsRealm.upmsUserService tocom.sun.proxy.$Proxy21。

主要是结尾处的com.sun.proxy.$Proxy21,出现了$Proxy21就说明用的还是JDK代理。

再换配置:

   <!-- 启动注解事务 -->
   <aop:aspectj-autoproxy proxy-target-class="true"/>
   <tx:annotation-driven  proxy-target-class="true"transaction-manager="mytransactionManager"/>

换了配置后上面的异常就没有了(也就是初始化spring容器通过了)。。。。。但是(初始化SpringMvc容器又报错)

org.springframework.beans.factory.BeanCreationException:Error creating bean with name 'upmsLogController': Injection of autowireddependencies failed; nested exception isorg.springframework.beans.factory.BeanCreationException: Could not autowirefield: private com.zhong.upms.service.UpmsLogServicecom.zhong.upms.controller.manage.UpmsLogController.upmsLogService; nestedexception is org.springframework.beans.factory.NoSuchBeanDefinitionException:No qualifying bean of type [com.zhong.upms.service.UpmsLogService] found fordependency: expected at least 1 bean which qualifies as autowire candidate forthis dependency. Dependency annotations:{@org.springframework.beans.factory.annotation.Autowired(required=true)}

报的还是注入问题,当然如果代码不正常的话可能有其他原因,这里的前提是代码没有书写错误(类名不一致、字母写错了等等之类),这里就还是代理的原因,换成用@Resource注解就能看出问题所在了(@ Autowired和@Resource区别,自行搜索),报的还是以com.sun.proxy.$Proxy结尾之类的错误,就是还有某个地方的代理还是JDK代理。

用过shiro的知道,要定义自定义的Realm,我的Realm:


经过上面的配置修改,我自定义的Realm是可以能够注入成功的,要不然shiro的shiroFilter也不会创建成功(shiro与spring结合的配置就不贴了,很大众,很容易搜)【这里也就是spring这个父容器创建成功了,而且内部也能够注解注入】,但是在Controller里却不能正常注入,报的就是Noqualifying bean of type一类的错误【这里说明springMvc这个子容器没有初始化成功,无法使用父容器的bean进行注入】。

为什么呢?困扰好久。。。。。。。。

后来发现了是因为二次代理造成的(究竟是不是二次代理不能保证,但在我看来是的)。

首先事务的代理是一层代理,其次还有一个在shiro配置时候的代理-----在用shiro的时候通常会有个配置,相信大家都在配置:

    <!-- 开启Shiro Spring AOP权限注解@RequiresPermissions的支持 -->
    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"depends-on="lifecycleBeanPostProcessor">
    </bean>
    <bean
    <!-- Shiro生命周期处理器-->
    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>

DefaultAdvisorAutoProxyCreator这个代理默认也是JDK代理,所以会出现错误,不过至今也不明白为什么会影响Controller层的注入!!!为什么?为什么?(求大神提点o(╥﹏╥)o)。

先不管为什么影响了,现在解决他,把他变成cglib代理:

    <!-- 开启Shiro Spring AOP权限注解@RequiresPermissions的支持 -->
    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"depends-on="lifecycleBeanPostProcessor">
       <property name="proxyTargetClass"value="true"/> 
    </bean>
    <!-- Shiro生命周期处理器-->
    <bean id="lifecycleBeanPostProcessor"class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>

没看错!!!就是加了属性<propertyname="proxyTargetClass"value="true"/> 

贴个启动成功的图先:


按理问题解决了,就结束了,但是还是有问题的(这个问题其实就是自己太菜,不明白):

把事务的配置还原为最初的配置即:<tx:annotation-driven transaction-manager="mytransactionManager"/>,发现还是可以正常启动,这又是为什么呢?为什么呢?为什么呢?为什么呢?。。。。

总结:

  1.如果项目框架spring+springMvc+mybatis(或类似框架),配置事务时如果要使用类的代理就要配置proxy-target-class="true",最有效的配置是再加一行配置:<aop:aspectj-autoproxyproxy-target-class="true"/>,即:

<!-- 启动注解事务 -->
   <aop:aspectj-autoproxy proxy-target-class="true"/>
   <tx:annotation-driven  proxy-target-class="true"transaction-manager="mytransactionManager"/>

 2.如果框架中有shiro,如果要用的代理是类的代理(cglib库),只要配置shiro出的代理即可:

  <!-- 开启Shiro Spring AOP权限注解@RequiresPermissions的支持 -->
  <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"depends-on="lifecycleBeanPostProcessor">
      <property name="proxyTargetClass"value="true"/> 
   </bean>
    <bean
    <!-- Shiro生命周期处理器-->
    <bean id="lifecycleBeanPostProcessor"class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>

注意:使用cglib库要用到相关包,我用的是cglib-3.1以及关联包asm-4.2(http://download.csdn.net/download/qq_33727653/10129795

 

 

 

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值