Struts2源码研究

一、Struts2容器初始化过程

1> 创建Dispatcher对象

    a> 将ServletContext设置到Dispatcher中

    b> 读取default.properties,struts-default.xml,struts-plugin.xml,struts.xml等配置文件

    c> 获取创建Container全局容器,在此期间会解析配置文件并创建xml文件中配置的Bean

    d> 使用ContainerHolder的静态方法将Container实例放入ThreadLocal中

    e> 初始化一些全局配置,比如是否为开发模式等

    f> 将Dispatcher对象放入Container全局容器中

2> 创建PrepareOperations和ExecuteOperations两个对象并将Dispatcher放入其中,之后doFilter会用到这两个对象

二、Struts2插件机制

介绍一下ObjectFactory类,它是创建对象的工厂,这些对象包括Action对象、结果类型、拦截器、验证器、类型转换器等。可以在struts.xml中配置

	<bean type="com.opensymphony.xwork2.ObjectFactory" name="smallbug" class="cn.smallbug.struts2.action.SmallbugFactory" />
	<constant name="struts.objectFactory" value="smallbug" />

 

SmallbugFactory是ObjectFactory的子类,以此来修改默认的对象工厂,spring插件也是配置这个参数达到了整合Struts2的目的。之所以可以这样做是因为在Struts2容器中很多地方都是调用了ObjectFactory的buildXxx方法来获取实例的。在运行时如果你给它配置了不同的子类,那么如何创建Action就有你来决定了。想使用某种工具直接可以将它的jar包放到部署目录下就ok,不想用直接取走,连配置文件都不用该极其灵活。这种灵活度的实现也得益于struts-default.xml,struts-plugin.xml,struts.xml配置文件的依次加载,出现重复的话后者覆盖前者。

三、Action核心流程(过滤器匹配成功时触发)

   

1> PrepareOperations对象设置结果集

2> PrepareOperations对象创建ActionContext

    a> Dispatcher获取ValueStackFactory的实例然后创建ValueStack

    b> 将request,request.getParameterMap(),session,servletContext分别封装成map

    c> 将上述所有Map放入一个大Map中以它们的名字作为key

    d> 获取ValueStack中名为context的Map,将上述大Map以putAll的方式添加进context中

    e> 创建一个ActionContext对象将ValueStack添加进去

3> 调用Dispatcher的静态setInstance方法,将Dispatcher实例放入ThreadLocal中

4> 将Request对象包装为StrutsRequestWrapper对象,其作用在于如果request域中找不到的属性会去stack中找

5> 根据request,response创建mapping映射对象

6> 使用ExecuteOperations执行目标方法

    a> 创建代理Action

        -> createAction(contextMap);创建Action:调用ObjectFactory中的buildAction方法创建action

        -> stack.push(action);把action放入到了栈顶

        -> 获取拦截器

    b> proxy.execute()执行代理方法,按照顺序的方式执行:

        -> 拦截器

        -> 执行action

        -> 执行结果集

        -> 如果拦截器的返回形式不是return invocation.invoke方法,则按照倒叙的方式执行

    c> 清空数据

四、拦截器调用原理

     首先是代理对象触发ActionInvocation实例的invoke方法,拦截器开始执行。ActionInvocation中有一个Iterator<InterceptorMapping>数据结构,保存着要依次执行的拦截器。看一下调用代码

 if (interceptors.hasNext()) {
                final InterceptorMapping interceptor = interceptors.next();
                String interceptorMsg = "interceptor: " + interceptor.getName();
                UtilTimerStack.push(interceptorMsg);
                try {
                                resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this);
                            }
                finally {
                    UtilTimerStack.pop(interceptorMsg);
                }
            } else {
                resultCode = invokeActionOnly();
            }

 

它其实是把自己的实例作为参数传了下去,这时候拦截器链上的节点执行会有两种情况

     1> return invocation.invoke();它会在执行完自己的逻辑之后返回ActionInvocation之后不再执行。

     2> invocation.invoke();//之后还有逻辑,它会在执行完自己的逻辑之后返回ActionInvocation,在ActionInvocation的逻辑执行完之后还会执行自己剩余的部分的逻辑。

猜你喜欢

转载自smallbug-vip.iteye.com/blog/2283668