以下代码简单模拟了通过struts2请求一个action时,struts2是怎样先执行其拦截器,然后再执行指定action的,通过此能初步理解struts2拦截器的执行原理。此代码还模拟展示了请求执行一个struts2 的 action的过程中当发生异常时,struts2是如何使用拦截器处理异常的。
代码没有完全按照struts2请求一个action时执行流,即先通过Dispatcher,利用actionConfig,ActionMapping,根据action名称查找对应的action,创建一个ActionProxy实例,然后执行其方法execute,execute方法再调用执行ActionInvocation的invoke方法(可以参考org.apache.struts2.dispatcher.Dispatcher的serviceAction方法)。这里只是简单创建了一个ActionProxy,一个ActionInvocation,调用ActionInvocation.invoke,模拟了struts2先执行拦截器,再执行action,然后再回来继续执行拦截器这个核心逻辑,尤其是在struts2对action调用执行过程中出现异常时,对弄清它处理异常的逻辑相当有帮助。
代码中,ActionInvocation的it成员变量初始化时保存了所有的拦截器(可以看做是一个拦截器栈)。从invoke方法的 interceptor.intercept(ActionInvocation.this) 可知,当执行一个action时,调用ActionInvocation的invoke方法,invoke方法内部迭代拦截器列表it,首先执行拦截器1,接着拦截器1又调回到invoke,invoke继续调用拦截器2,依次类推,直至拦截器按照入栈出栈的顺序执行完毕。invoke中对拦截器的调用,可以看做是拦截器调用拦截器的逻辑。
注意拦截器栈中的拦截器执行时,入栈出栈的执行轨迹,action是在最后一个拦截器出栈执行时被调用执行的:当最后一个拦截器出栈执行,调用到ActionInvocation的invoke方法,invoke方法这时才去调用执行action。action执行完返回,之前入栈的拦截器会依次出栈,从上次执行中断处继续执行(如果发现有异常抛上来,则只执行到中断处,执行finally)。即拦截器的执行顺序是,action执行前:1,2,3,action执行后:3,2,1。
根据拦截器栈的执行顺序,struts2把处理异常的拦截器放在栈顶,即action执行前第一个执行,action执行完毕返回或中间拦截器执行异常返回后作为最后一个拦截器执行。这样,无论是action执行异常,还是拦截器执行异常,异常抛出时按照拦截器栈执行轨迹,异常最终被抛至最后出栈执行的拦截器1中,即被专门处理异常的拦截器catch住。
struts2里面,这样的异常处理拦截器是 ExceptionMappingInterceptor,跟其他拦截器的区别是它会把异常catch住(其他的拦截器只负责把异常throw出去),并查找客户端在struts配置文件中配置好的exception-mapping(局部或全局),返回exception-mapping的result,这样的result一般是客户端定义跳转到错误页面去。你可以在自定义拦截器时放开ExceptionMappingInterceptor的对写日志的限制,允许在ExceptionMappingInterceptor捕获到异常时写日志,参考这里:
如果客户端没有定义exception-mapping,ExceptionMappingInterceptor会把异常throw出去。
模拟代码如下 :
public class Struts2ActionInvocationTest { public static void main(String[] args)throws Exception{ List<Inteceptor> list = new ArrayList<Inteceptor>(); Interceptor1 interceptor1 = new Interceptor1(); list.add(interceptor1); Interceptor2 interceptor2 = new Interceptor2(); list.add(interceptor2); Interceptor3 interceptor3 = new Interceptor3(); list.add(interceptor3); ActionInvocation a = new ActionInvocation(); MyAction action = new MyAction(); ActionProxy proxy = new ActionProxy(null,action); a.init(list,proxy); a.invoke(); } //action定义 private static class MyAction{ public String execute()throws Exception{ System.out.println("All interceptors finished first time,Action execute here"); if(true){ //特地抛异常,搞清struts2的异常处理机制 throw new Exception("action execute error"); } return "success"; } } //action代理定义 private static class ActionProxy{ private Object action; private String method; public ActionProxy(String method,Object action){ this.action = action; if(method == null){ method = "execute"; } this.method = method; } public Object getAction() { return action; } public String getMethod() { return method; } } //action调用 private static class ActionInvocation{ private Iterator<Inteceptor> it; private String resultCode; private ActionProxy proxy; public void init(List<Inteceptor> interceptors,ActionProxy proxy){ it = interceptors.iterator(); this.proxy = proxy; } public String invoke()throws Exception{ if(it.hasNext()){ Inteceptor interceptor = it.next(); try { System.out.println(interceptor.toString().concat(" start.........")); resultCode = interceptor.intercept(ActionInvocation.this); } finally { System.out.println(interceptor.toString().concat(" finished,result = " + resultCode)); } }else{ //the last interceptor execute here when invoke this method, // then invoke action resultCode = (String) this.invokeAction(); } return resultCode; } public Object invokeAction()throws Exception{ try { Method method1 = proxy.getAction().getClass().getMethod(proxy.getMethod()); return method1.invoke(proxy.getAction(),new Object[0]); }catch (NoSuchMethodException ex){ throw new IllegalArgumentException("The " + proxy.getMethod() + "() is not defined in action " + proxy.getAction().getClass() + ""); }catch (InvocationTargetException ex) { //InvocationTargetException已把cause转为null,这里拿出原ex Throwable t = ex.getTargetException(); if(t instanceof Exception){ throw (Exception)t; }else{ throw ex; } } } } //拦截器定义 private interface Inteceptor{ public String intercept(ActionInvocation a)throws Exception; } private static class Interceptor1 implements Inteceptor{ @Override public String intercept(ActionInvocation a) throws Exception{ try{ return a.invoke(); }catch (Exception ex){ System.err.println("exception handle by Interceptor1 :" + ex.getMessage()); } return null; } public String toString(){ return "Interceptor1"; } } private static class Interceptor2 implements Inteceptor{ public String intercept(ActionInvocation a) throws Exception{ return a.invoke(); } public String toString(){ return "Interceptor2"; } } private static class Interceptor3 implements Inteceptor{ public String intercept(ActionInvocation a) throws Exception{ return a.invoke(); } public String toString(){ return "Interceptor3"; } } }
执行打印的结果:
Interceptor2 start.........
Interceptor3 start.........
All interceptors finished first time,Action execute here
Interceptor3 finished,result = null
Interceptor2 finished,result = null
Interceptor1 finished,result = null
exception handle by Interceptor1 :action execute error
注意红色字体部分,是调用执行action时发生异常,最终抛至拦截器1时被捕获。拦截器1被定义成负责异常处理的类。
下面是struts2的DefaultActionInvocation类部分源码,DefaultActionInvocation的invoke方法中,如果拦截器列表存在拦截器,会依次执行拦截器的intercept方法,而拦截器的intercept方法又会调用DefaultActionInvocation的invoke方法,继续执行列表的下一个拦截器。即以拦截器调用拦截器的方式,action执行完(或有异常),根据拦截器的执行顺序,依次出栈从上次执行中断处继续执行(如果发现有异常就从中断处返回,执行finally块):
//@see com.opensymphony.xwork2.DefaultActionInvocation#invoke public String invoke() throws Exception { String profileKey = "invoke: "; try { UtilTimerStack.push(profileKey); if (executed) { throw new IllegalStateException("Action has already executed"); } //拦截器递归调用执行 if (interceptors.hasNext()) { final InterceptorMapping interceptor = (InterceptorMapping) interceptors.next(); String interceptorMsg = "interceptor: " + interceptor.getName(); UtilTimerStack.push(interceptorMsg); try { resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this); } finally { UtilTimerStack.pop(interceptorMsg); } } else { //最后一个拦截器执行完后,执行action resultCode = invokeActionOnly(); } ... }
相关推荐
在文章"Struts2拦截器原理分析实例"中,作者通过一个具体的应用场景,展示了如何配置和使用拦截器来实现特定的功能,比如日志记录或权限验证。通过阅读这篇博客,我们可以更直观地理解拦截器的工作方式和价值。 ...
以下是对Struts2拦截器原理与实现的详细解析: 1. **拦截器的概念** Struts2拦截器是一种AOP(面向切面编程)的实现,它可以在不修改Action代码的情况下,通过定义拦截器并在配置文件中设置拦截器链,来动态地添加...
这篇文章将深入探讨Struts2拦截器的概念、工作原理以及如何在实际应用中使用它们。 **一、什么是Struts2拦截器** 拦截器是基于AOP(面向切面编程)思想的组件,它可以理解为在Action调用前后插入的逻辑处理。在...
2. **拦截器链**:在Struts2中,多个拦截器可以形成一个拦截器链,每个拦截器按照定义的顺序依次执行。如果所有拦截器都允许Action执行,那么Action的结果将被传递到下一个拦截器,直到整个链执行完毕。 ### 二、...
这些拦截器按照配置的顺序逐个执行,每个拦截器执行完毕后,会将控制权传递给下一个拦截器,直到最后一个拦截器执行完后再调用Action的`execute`方法。当`execute`方法执行完毕,控制权会反向传递回之前的拦截器,...
通过对Struts2拦截器的深入分析,我们可以看出拦截器不仅是Struts2框架的核心组成部分,也是实现代码重用、提高代码质量的有效手段。理解并合理运用拦截器,对于提升项目的开发效率和代码质量具有重要意义。
通过这两个实例,你将更深入地理解Struts2拦截器的工作原理和配置方式,以及它们如何在实际项目中发挥作用。记得在实践中多尝试,理解拦截器如何与其他Struts2组件协作,以提升你的Web应用开发技能。
在Struts2中,拦截器的工作原理如下: 1. 用户发起HTTP请求,请求到达Struts2的Front Controller(DispatcherServlet)。 2. DispatcherServlet会根据配置找到对应的Action(动作)类。 3. 在调用Action之前,...
这篇博客“Struts2 拦截器的执行顺序(二十九)”可能探讨了Struts2拦截器链的工作原理和它们的执行顺序,这对于理解Struts2的内部机制至关重要。 首先,让我们深入理解Struts2的拦截器。拦截器是在Action调用前后...
首先,我们需要了解Struts2中的拦截器工作原理。拦截器是基于Java的动态代理模式实现的,它们按照配置的顺序在Action执行之前和之后执行。通过实现`Interceptor`接口或继承`AbstractInterceptor`类,我们可以创建...
Struts2框架中的拦截器(Interceptor)是一种重要的机制,用于在Action执行前后进行一系列处理,比如参数验证、数据预处理等。它能够帮助开发者更加灵活地控制程序流程,提高代码的复用性。 #### 二、Struts2拦截器...
在Struts2中,拦截器(Interceptor)扮演着核心角色,它们允许开发者在动作执行前后插入自定义的逻辑,如日志、权限检查、数据验证等。本示例将探讨如何在Struts2中使用拦截器。 首先,我们需要理解Struts2拦截器的...
分析这个文件或目录可以帮助我们更深入地理解Struts2拦截器的内部工作机制,包括它如何与ActionInvocation交互,以及如何处理请求和响应。 总结来说,Struts2拦截器是框架的核心部分,它们提供了一种灵活的方式,以...
本篇文章将深入剖析Struts2拦截器的工作原理,并通过案例"struts007"来展示如何实际应用。 首先,我们了解下拦截器的基本概念。拦截器是一个实现了Struts2提供的`Interceptor`接口的类,它定义了两个方法:`...
下面将详细探讨Struts2拦截器的源码及其工作原理。 首先,理解拦截器的定义:拦截器是AOP(面向切面编程)的一个概念,在Struts2中,拦截器是基于Java的动态代理机制实现的。它们是一系列实现了`Interceptor`接口的...
在本篇文章中,我们将深入探讨Struts2的拦截器原理以及如何在实际项目中应用拦截器。 拦截器在Struts2中的作用就像电影中的导演,它在动作执行前后插入额外的逻辑,比如日志记录、权限检查、数据验证等。这些操作不...
首先,我们需要了解Struts2拦截器的工作原理。拦截器是基于AOP(面向切面编程)思想实现的,它通过在Action调用前后插入额外的操作,形成一个拦截链。当一个请求到来时,Struts2会按照配置的顺序依次执行这些拦截器...
当拦截器执行完毕,ActionInvocation负责调用实际的Action方法。 4. **Before和After**:每个拦截器有两个主要方法,`intercept()`方法会在Action执行之前被调用,而`afterCompletion()`方法则在Action执行完毕后...
Struts2的拦截器执行流程如下: 1. **初始化拦截器栈**:当Struts2框架启动时,会根据配置文件(struts.xml)中的配置信息,创建一个拦截器栈。这个栈包含了所有需要执行的拦截器,它们按照配置的顺序排列。 2. **...