`
weick
  • 浏览: 69172 次
  • 性别: Icon_minigender_1
  • 来自: 天堂的隔壁
社区版块
存档分类
最新评论

struts2拦截器的执行原理分析

阅读更多

 

以下代码简单模拟了通过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 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";
        }
    }

}

 

执行打印的结果:

 

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

  

分享到:
评论

相关推荐

    struts2拦截器原理

    在action执行之前先进行拦截器的拦截处理,然后再执行action的execute方法,返回给拦截器,再对应相应result

    Struts拦截器及token拦截器防止重复提交例子源码

    Struts2拦截器的实现原理相对简单,当请求struts2的action时,Struts 2会查找配置文件,并根据其配置实例化相对的 拦截器对象,然后串成一个列表,最后一个一个地调用列表中的拦截器 三、定义Struts2拦截器。 ...

    struts2拦截器时序图

    struts2拦截器,里面介绍了struts2拦截器的执行的原理,用了非常生动的例子讲解了struts2执行过程。

    Struts2拦截器Interceptor的原理与配置实例详解

    拦截器是一种AOP(面向切面编程)思想的编程方式.它提供一种机制是开发者能够把相对独立的代码抽离出来,...下面这篇文章主要给大家介绍了关于Struts2拦截器Interceptor的原理与配置的相关资料,需要的朋友可以参考下。

    Struts2的工作原理和流程

    7 ActionInvocation实例使用命名模式来调用,在调用Action的过程前后,涉及到相关拦截器(Intercepter)的调用。 8 一旦Action执行完毕,ActionInvocation负责根据struts.xml中的配置找到对应的返回结果。返回结果...

    Java中的Struts2框架拦截器之实例代码

    在看拦截器的小例子的前我们先来看看sturts2的原理   struts2自己是有拦截器的,通过拦截器可以拦截用户请求,并作出处理 拦截器作用有很多,譬如: 1.Action里面有个属性,这个属性我想在action执行之前改成别的值...

    Struts2入门教程(全新完整版)

    一、准备工作及实例 3 1.解压struts-2.1.6-all.zip 3 2.六个基本包 3 3.初识struts2配置文件 4 ... 下面对struts2的基本执行流程作一简要说明,此流程说明可以结合官方提供的struts2结构图来看: 60

    struts2流程与流程图

    但在调用之前,ActionInvocation会根据配置加载Action相关的所有Interceptor(拦截器)。  一旦Action执行完毕,ActionInvocation负责根据struts.xml中的配置找到对应的返回结果result。 Struts 2的核心控制器是...

    struts2开发文档

    struts2的所有知识点 流程 原理 一个请求在Struts2框架中的处理大概分为以下几个步骤: 1 客户端初始化一个指向Servlet容器(例如Tomcat)的请求; 2 这个请求经过一系列的过滤器(Filter)(这些过滤器中有一个...

    计算机科学系毕业设计论文范文

    Struts 2以WebWork为核心,采用拦截器的机制来处理用户的请求,这样的设计也使得业务逻辑控制器能够与Servlet API完全脱离开,所以Struts 2可以理解为WebWork的更新产品。因为Struts 2和Struts 1有着太大的变化,...

    SpringMVC面试专题.pdf

    1、什么是 SpringMvc? 2、Spring MVC 的优点: 3、SpringMVC 工作原理? 4、SpringMVC 流程? 6、SpringMvc 的控制器是不是单例模式,如果是,有...22、SpringMvc 里面拦截器是怎么写的 23、讲下 SpringMvc 的执行流程

    Spring攻略(第二版 中文高清版).part2

    8.3 用处理程序拦截器拦截请求 297 8.3.1 问题 297 8.3.2 解决方案 298 8.3.3 工作原理 298 8.4 解析用户区域 302 8.4.1 问题 302 8.4.2 解决方案 302 8.4.3 工作原理 302 8.5 外部化区分区域的...

    Java面试宝典2020修订版V1.0.1.doc

    拦截器和过滤器的区别? 91 11、struts.xml中result的type有哪些类型? 91 12、什么时候用JDBC什么时候用Hibernete; 91 13、hibernate 数据的三个状态 91 14、Hibernate中load和get的区别? 92 15、Hibernate的工作...

    Java学习笔记-个人整理的

    \contentsline {chapter}{Contents}{2}{section*.1} {1}Java基础}{17}{chapter.1} {1.1}基本语法}{17}{section.1.1} {1.2}数字表达方式}{17}{section.1.2} {1.3}补码}{19}{section.1.3} {1.3.1}总结}{23}{...

    JAVA程序开发大全---上半部分

    8.2.3 Struts配置文件编辑器 124 8.3 Struts应用实例:登录系统 125 8.4 本章小结 133 第9章 Hibernate框架的开发及应用 134 9.1 Hibernate框架概述 134 9.1.1 O/R Mapping(对象/关系映射)技术 134 9.1.2 ...

    Spring攻略(第二版 中文高清版).part1

    8.3 用处理程序拦截器拦截请求 297 8.3.1 问题 297 8.3.2 解决方案 298 8.3.3 工作原理 298 8.4 解析用户区域 302 8.4.1 问题 302 8.4.2 解决方案 302 8.4.3 工作原理 302 8.5 外部化区分区域的...

    最新Java面试题视频网盘,Java面试题84集、java面试专属及面试必问课程

    │ Java面试题49.Struts2的拦截器是什么?你都用它干什么?.mp4 │ Java面试题50.Spring MVC的执行流程.mp4 │ Java面试题51.SpringMVC和Struts2的不同.mp4 │ Java面试题52.简单介绍一下Spring或者Spring的两大核心...

    2021年最新java面试题--视频讲解(内部培训84个知识点超详细).rar

    Java面试题49.Struts2的拦截器是什么 Java面试题50.Spring MVC的执行流程 Java面试题51.SpringMVC和Struts2的不同 Java面试题52.简单介绍一下Spring或者Spring的两大核心 Java面试题53.AOP是什么?都用它做什么? ...

    java面试题

    finalize是Object的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法。 assert是什么?什么时候用到? 答:断言,可以将断言看成是异常处理的一种高级形式,可以用来判断某个特定的表达式或值是否为真。 ...

    Spring面试题

    基于Struts开发的应用由3类组件构成:控制器组件、模型组件、视图组件 8. Struts的validate框架是如何验证的? 在struts配置文件中配置具体的错误提示,再在FormBean中的validate()方法具体调用。 9. 说下Struts...

Global site tag (gtag.js) - Google Analytics