原因是:
struts1.x中,当一个请求到来的时候交给了org.apache.struts.action.RequestProcessor这个类进行处理,这是该类中一方法的源代码:
protected ActionForward processActionPerform(HttpServletRequest request, HttpServletResponse response, Action action, ActionForm form, ActionMapping mapping) throws IOException, ServletException { try { return (action.execute(mapping, form, request, response)); } catch (Exception e) { return (processException(request, response, e, form, mapping)); } }在这个方法中调用了action的execute方法,当然在自己定义的Action中是没有execute这个方法的,也就是spring为其生成的代理类也没有execute方法,而DispatchAction中重写了org.apache.struts.action.Action中的execute方法,所以这里所执行的也就是DispatchAction中的execute方法,在DispatchAction中的execute方法内部,根据自定义Action配置参数与请求参数通过反射动态调用了自定义Action中的方法,这是源代码:
Object args[] = {mapping, form, request, response}; forward = (ActionForward) method.invoke(this, args);注意我们自定义Action中的方法是通过反射动态调用的,执行的方法是自定义Action中的方法,并不是代理Action中的方法,代理类Action中的方法是应用上了通知的,但由于DispatchAction的执行流程"巧妙"地绕过了代理Action中的方法直接执行了自定义Action目标类的方法,所以也就无法应用上通知了。如果能把method.invoke(this,args)中的this替换成代理Action实例,这样就能应用上通知了,而获取代理类实例是件麻烦事,虽然后来struts1.x提供了获取代理类实例的工具类,但是还是得修改源代码,入侵性太强,不宜采取,所以spring AOP在struts1.x中是行不通的。
但是我们可以通过自定义aop实现spring AOP类似的功能,上面说到请求到时交给了RequestProcessor这个类进行处理,而使用struts1.x的时候一般都会集成进spring,RequestProcessor这个类是可配置的,集成进spring后,请求就是交给了spring的org.springframework.web.struts.DelegatingRequestProcessor实现,如果我们自己写一个继承自spring的org.springframework.web.struts.DelegatingRequestProcessor类,覆盖其process方法进行权限判断,如果有权限则调用父类的process方法,如果没有权限则返回指向无权限提示页面的ActionForward.
只要在struts-config.xml文件中配置上自己的RequestProcessor类,这样就也能实现权限拦截了。
在struts2中,Action是个接口,其中只有一个execute方法,所以默认情况下cglib会选用JDK提供的Proxy生成代理类,代理类中也就只有一个execute方法,如果在我们自定义的Action中的执行方法名不是execute就会报方法不存在例外,这时就需要更改配置:<aop:aspectj-autoproxy proxy-target-class="true"/>,proxy-target-class属性值设置为true,而默认为false,这样就不管目标类有无实现接口都使用cglib生成代理类,这样代理类中就都有我们自定义Action中的方法了,需要注意的是,因为我们会在自定义Action中定义getter、setter方法,有可能还很多,而这些方法是不需要拦截的,所以在定义切面的时候应该把这些方法排除在外。当然中struts中不使用spring的AOP实现权限拦截也是可以的,只要写一个Interceptor拦截所有需要被拦截的Action,在该权限拦截器中进行权限校验,再根据校验的结果决定导向哪一个视图。
差不多了,就到这吧。