Shiro与AspectJ的配置 Shiro的配置 根据 个人BLOG文章和官方文档咱们能够得知Shiro在使用注解的时的配置是html
根据 个人BLOG文章和官方文档咱们能够得知Shiro在使用注解的时的配置是java
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"/> <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"> <property name="securityManager" ref="securityManager"/> </bean>
其基于注解的权限控制功能git
根据上文,启用基于注解的AspectJ就很简单了,由于基于注解的Shiro通常也在SpringMVC的Context里,咱们采用以下配置github
<aop:aspectj-autoproxy proxy-target-class="true"/>
在二者分别配置的时候,配置方法都是对的可是一旦公用,会发现AspectJ会失效web
解决办法也很简单,注释掉Shiro配置中的第一句spring
<!--<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"/>-->
注释以后Shiro的注解权限管理功能并不会失效,具体缘由咱们来细细分析apache
给DefaultAdvisorAutoProxyCreator加入参数proxyTargetClass为true编程
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"> <property name="proxyTargetClass" value="true"/> </bean>
缘由在于二次代理api
为何会肯定是这个缘由,废了我好大功夫,详情请看代码追踪。。。。没精力就别看了网络
在配置文件中的 aop:aspectj-autoproxy会最终交给名为 AopNamespaceHandler的类进行处理,进入该类(直接在工程全局搜)咱们能够看到
public class AopNamespaceHandler extends NamespaceHandlerSupport { public AopNamespaceHandler() { } public void init() { this.registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser()); this.registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser()); this.registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator()); this.registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser()); } }
aspectj-autoproxy 是由 AspectJAutoProxyBeanDefinitionParser 注册的,而后根据 该Blog提出的说法
该Blog做者提出,因为
<aop:aspectj-autoproxy/> 方式对应的注册AutoProxyCreator 的方法是:registerAspectJAnnotationAutoProxyCreatorIfNecessary DefaultAdvisorAutoProxyCreator 方式对应的注册AutoProxyCreator 的方法是:registerAutoProxyCreatorIfNecessary;
最终会在第七步骤的函数里,因为这个if…else判断致使不能存在两个代理,因此不能混合使用 DefaultAdvisorAutoProxyCreator与 aop:aspectj-autoproxy
这个结论是错误的,是由于DefaultAdvisorAutoProxyCreator不会调用registerAutoProxyCreatorIfNecessary,产生错误的缘由是 二次代理 做者追踪错了代码,只是恰巧改对了
来,跟着我找 DefaultAdvisorAutoProxyCreator 如何建立代理的代码
这也是咱们在文章一中所说的,一般状况下Spring使用针对接口的JDK代理进行动态代理,绕了这么久,咱们回到第五步,看 createProxy方法如何使用 ProxyFactory对象
以上完成了 DefaultAdvisorAutoProxyCreator 动态代理的建立
有一些文章分析给出 没法肯定二次代理的状况下哪一个代理成功,可是根据我自己追踪日志发现,在Spring启动时,个人切面类日志输出成功
[2016-10-23 14:00:13][qtp1938298155-28][INFO ][] c.b.psas.web.aspect.ControllerLogAspect 28 -- 网络请求开始 RequestURL: / RequestVO参数: null [2016-10-23 14:00:13][qtp1938298155-28][INFO ][] c.b.psas.web.aspect.ControllerLogAspect 33 -- 网络请求结束 RequestURL: / RequestVO参数: null
可是在调用接口时,开启DEBUG日志,会发现Shiro抛出的异常为
[2016-10-23 13:38:52][qtp1386909980-27][DEBUG][] o.s.web.servlet.DispatcherServlet 1197 -- Handler execution resulted in exception - forwarding to resolved error view: ModelAndView: reference to view with name '/errors/500'; model is {exception=java.lang.IllegalStateException: The mapped controller method class 'com.bestpay.psas.web.controller.manage.LoginController' is not an instance of the actual controller bean class 'com.sun.proxy.$Proxy103'. If the controller requires proxying (e.g. due to @Transactional), please use class-based proxying. HandlerMethod details: Controller [com.bestpay.psas.web.controller.manage.LoginController] Method [public java.lang.String com.bestpay.psas.web.controller.manage.LoginController.login()] Resolved arguments: } java.lang.IllegalStateException: The mapped controller method class 'com.bestpay.psas.web.controller.manage.LoginController' is not an instance of the actual controller bean class 'com.sun.proxy.$Proxy103'. If the controller requires proxying (e.g. due to @Transactional), please use class-based proxying. HandlerMethod details: Controller [com.bestpay.psas.web.controller.manage.LoginController] Method [public java.lang.String com.bestpay.psas.web.controller.manage.LoginController.login()] Resolved arguments: at org.springframework.web.method.support.InvocableHandlerMethod.assertTargetBean(InvocableHandlerMethod.java:262) ~[spring-web-4.1.9.RELEASE.jar:4.1.9.RELEASE] at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:225) ~[spring-web-4.1.9.RELEASE.jar:4.1.9.RELEASE] at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137) ~[spring-web-4.1.9.RELEASE.jar:4.1.9.RELEASE] at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110) ~[spring-webmvc-4.1.9.RELEASE.jar:4.1.9.RELEASE] at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:775) ~[spring-webmvc-4.1.9.RELEASE.jar:4.1.9.RELEASE] at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:705) ~[spring-webmvc-4.1.9.RELEASE.jar:4.1.9.RELEASE] at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) ~[spring-webmvc-4.1.9.RELEASE.jar:4.1.9.RELEASE] at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959) [spring-webmvc-4.1.9.RELEASE.jar:4.1.9.RELEASE] at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893) [spring-webmvc-4.1.9.RELEASE.jar:4.1.9.RELEASE] at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:965) [spring-webmvc-4.1.9.RELEASE.jar:4.1.9.RELEASE] at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:856) [spring-webmvc-4.1.9.RELEASE.jar:4.1.9.RELEASE] at javax.servlet.http.HttpServlet.service(HttpServlet.java:735) [servlet-api-3.0.jar:na] at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:841) [spring-webmvc-4.1.9.RELEASE.jar:4.1.9.RELEASE] at javax.servlet.http.HttpServlet.service(HttpServlet.java:848) [servlet-api-3.0.jar:na] at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:684) [jetty-servlet-8.1.17.v20150415.jar:8.1.17.v20150415] at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1496) [jetty-servlet-8.1.17.v20150415.jar:8.1.17.v20150415] at org.apache.shiro.web.servlet.AbstractShiroFilter.executeChain(AbstractShiroFilter.java:449) [shiro-web-1.2.4.jar:1.2.4] at org.apache.shiro.web.servlet.AbstractShiroFilter$1.call(AbstractShiroFilter.java:365) [shiro-web-1.2.4.jar:1.2.4] at org.apache.shiro.subject.support.SubjectCallable.doCall(SubjectCallable.java:90) [shiro-core-1.2.4.jar:1.2.4] at org.apache.shiro.subject.support.SubjectCallable.call(SubjectCallable.java:83) [shiro-core-1.2.4.jar:1.2.4] at org.apache.shiro.subject.support.DelegatingSubject.execute(DelegatingSubject.java:383) [shiro-core-1.2.4.jar:1.2.4] at org.apache.shiro.web.servlet.AbstractShiroFilter.doFilterInternal(AbstractShiroFilter.java:362) [shiro-web-1.2.4.jar:1.2.4] at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125) [shiro-web-1.2.4.jar:1.2.4] at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:344) [spring-web-4.1.9.RELEASE.jar:4.1.9.RELEASE] at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:261) [spring-web-4.1.9.RELEASE.jar:4.1.9.RELEASE]
能够在日志中发现几个关键字
三个关键字分别说明了
由于Shiro也是基于Spring的AOP类的,若是找不到合适的配置,就是默认采用同一个Context下的AOP代理配置,咱们给了其proxy-target-class为true,天然就在第二次代理的时候找获得方法
方法二就更直接了,告诉DefaultAdvisorAutoProxyCreator为True就好
我之前写过另外一个文章,讨论了 SpringMVC和Spring公用的状况下Transactional失效的问题颇有可能底层缘由也是二次代理