以下代码简单模拟了通过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捕获到异常时写日志,参考这里:

http://struts.apache.org/release/2.1.x/struts2-core/apidocs/com/opensymphony/xwork2/interceptor/ExceptionMappingInterceptor.html

如果客户端没有定义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 actionresultCode = (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,这里拿出原exThrowable 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{@Overridepublic 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";}}}

执行打印的结果:

Interceptor1 start.........
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 { //最后一个拦截器执行完后,执行actionresultCode = invokeActionOnly();}...}

struts2拦截器的执行原理分析相关推荐

  1. struts2拦截器的实现原理及源码剖析

    拦截器(interceptor)是Struts2最强大的特性之一,也可以说是struts2的核心,拦截器可以让你在Action和result被执行之前或之后进行一些处理.同时,拦截器也可以让你将通用的 ...

  2. Struts2→拦截器、工作原理、拦截器计算Action执行时间、Struts2自带拦截器、拦截器栈

    工作原理 实现拦截器 样例 Struts2自带拦截器 拦截器栈(先进后出) TOKEN防表单重复提交 文字拦截器 AJAX

  3. Struts2 拦截器(Interceptor )原理和配置

    Struts2 拦截器 拦截器在概念上与servlet过滤器或JDK代理类相同.拦截器允许横切功能,把action以及框架分开实现.你可以使用拦截器实现以下操作: 在调用action之前提供预处理逻辑 ...

  4. 从struts2拦截器到自定义拦截器

    http://www.cnblogs.com/withyou/p/3170440.html 拦截器可谓struts2的核心了,最基本的bean的注入就是通过默认的拦截器实现的,一般在struts2.x ...

  5. struts2拦截器简介

    2019独角兽企业重金招聘Python工程师标准>>> 一.理解Struts2拦截器 1. Struts2拦截器是在访问某个Action或Action的某个方法,字段之前或之后实施拦 ...

  6. Struts2拦截器(Interceptor)原理详解

    1.    理解拦截器 1.1.    什么是拦截器: 拦截器,在AOP(Aspect-Oriented Programming)中用于在某个方法或字段被访问之前,进行拦截然后在之前或之后加入某些操作 ...

  7. Struts2第七篇【介绍拦截器、自定义拦截器、执行流程、应用】

    什么是拦截器 拦截器Interceptor-..拦截器是Struts的概念,它与过滤器是类似的-可以近似于看作是过滤器 为什么我们要使用拦截器 前面在介绍Struts的时候已经讲解过了,Struts为 ...

  8. 「深入源码」Spring拦截器的实现原理和执行机制

    我一直以为Spring的拦截器是基于AOP原理实现的,仔细阅读完源码,才知道自己的认知是错误的. 今天我们就从源码的角度剖析下Spring拦截器. 一.创建一个自己的拦截器 实现一个自己的拦截器,需要 ...

  9. Struts2_day04--课程介绍_Struts2拦截器概述底层原理_重要的概念

    Struts2_day04 上节内容 今天内容 Struts2拦截器概述 拦截器底层原理 重要的概念 自定义拦截器 自定义登录拦截器 Struts2的标签库 Struts2表单标签(会用) Strut ...

  10. Struts2拦截器的使用

    如何使用struts2拦截器,或者自定义拦截器.特别注意,在使用拦截器的时候,在Action里面必须最后一定要引用struts2自带的拦截器缺省堆栈defaultStack,如下(这里我是引用了str ...

最新文章

  1. mac 黑窗口连接mysql_Mac下安装配置MySQL
  2. sdi转hdmi转换器应用领域及规格参数详解
  3. 混凝土地坪机器人_地面整平机器人:精准又高效,轻松摆“平”混凝土
  4. docker tomcat:9.0
  5. wifi 信道_WiFi网速太慢,四招就可以让无线网络变得顺畅
  6. 【课后习题】数值计算方法期末复习
  7. DWR第四篇之对象传参
  8. Android百分比布局支持和垂直TextView
  9. 今天的阿里云,不应该只是这张图
  10. 2019年宁波高职技能考计算机,2019年宁波职业技术学院高职提前招生考试综合素质测试大纲...
  11. 软件设计文档编写概述
  12. java中this和this()区别
  13. C语言股票交易软件,甩手掌柜股票自动交易程序(2021年5月版)
  14. ECMAScript
  15. mybatis insert返回自增主键的id值
  16. 计算机绘画小房子教案,中班绘画《房子》教案
  17. css如何去掉图片里面存在的背景色
  18. 二维dct变换例题_数字图像处理试题(带答案)
  19. 强化学习-Q-Learning算法
  20. Java中的大端和小端

热门文章

  1. php 字符串编码方式转换,php字符串编码转换的常用几种方法_PHP教程
  2. Windows Server 2003 AGP纹理加速无法打开问题可行的解决方案
  3. html学习——介绍
  4. Java Attach机制
  5. 森林老是显示连接服务器超时,乌鸦森林之谜3:卡赫拉之影无法连接服务器是什么原因...
  6. docker attach 和 exec 的区别
  7. 无心剑英译秦观《鹊桥仙》
  8. 各种光纤接口类型介绍
  9. 基于51单片机的555定时器测电容proteus仿真
  10. PowerBI 开发 第22篇:发现异常(Find Anomalies)