Spring AOP与struts1.x,struts2.x的结合

spring AOP用于做权限拦截是一个很好的选择.spring AOP其拦截的原理就是生成目标类的代理类对目标类应用通知(advice)
通知类型有:
前置通知
后置通知
最终通知
例外通知
环绕通知


由各种通知的特点可知,只有环绕通知才适用于对目标类方法实施拦截。
spring AOP生成代理类是通过JDK提供的Proxy这个动态代理类或CGLib生成动态代理,缺省情况下,如果目标类实现了某个或某些接口,spring会选择JDK提供的Proxy生成代理,如果目标类没有实现接口则会使用CGLib通过继承自目标类生成目标类的子类生成代理类。对于没有实现接口的目标类则只能使用CGLib生成代理,JDK提供的Proxy是无能为力的,因为Proxy必须提供接口,但对于实现了接口的目标类,使用哪种方式生成代理类是可配置的。


在struts1.x中我们是通过继承org.apache.struts.action.Action来定义我们的Action,因为这是个类继承自Object,没有实现任何接口,也就是我们自己写的Action也没有实现任何接口,这时就是使用CGLib生成代理类。如果在struts1.x中,定义自己的Action的时候最多的就是继承org.apache.struts.action.Action和org.apache.struts.actions.DispatchAction
,当继承DispatchAction的时候你会发现spring的AOP并不能为Action应用上通知(advice),但继承自Action的时候却是可以的,这是为什么呢?


原因是:
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,在该权限拦截器中进行权限校验,再根据校验的结果决定导向哪一个视图。

差不多了,就到这吧。

你可能感兴趣的:(spring,AOP,struts2,struts1,权限拦截)