读书人

转载:Struts2源码分析-请求处理

发布时间: 2012-12-21 12:03:49 作者: rapoo

转载:Struts2源码分析--请求处理
转载:http://www.blogjava.net/myyate/articles/Struts2_source_java.html



请求首先通过Filter chain,Filter主要包括ActionContextCleanUp,它主要清理当前线程的ActionContext和Dispatcher;FilterDispatcher主要通过AcionMapper来决定需要调用哪个Action。
ActionMapper取得了ActionMapping后,在Dispatcher的serviceAction方法里创建ActionProxy,ActionProxy创建ActionInvocation,然后ActionInvocation调用Interceptors,执行Action本身,创建Result并返回,当然,如果要在返回之前做些什么,可以实现PreResultListener。

Struts2部分类介绍
这部分从Struts2参考文档中翻译就可以了。
ActionMapper
ActionMapper其实是HttpServletRequest和Action调用请求的一个映射,它屏蔽了Action对于Request等java Servlet类的依赖。Struts2中它的默认实现类是DefaultActionMapper,ActionMapper很大的用处可以根据自己的需要来设计url格式,它自己也有Restful的实现,具体可以参考文档的docs\actionmapper.html。
ActionProxy&ActionInvocation
Action的一个代理,由ActionProxyFactory创建,它本身不包括Action实例,默认实现DefaultActionProxy是由ActionInvocation持有Action实例。ActionProxy作用是如何取得Action,无论是本地还是远程。而ActionInvocation的作用是如何执行Action,拦截器的功能就是在ActionInvocation中实现的。
ConfigurationProvider&Configuration
ConfigurationProvider就是Struts2中配置文件的解析器,Struts2中的配置文件主要是尤其实现类XmlConfigurationProvider及其子类StrutsXmlConfigurationProvider来解析,

Struts2请求流程
1、客户端发送请求
2、请求先通过ActionContextCleanUp-->FilterDispatcher
3、FilterDispatcher通过ActionMapper来决定这个Request需要调用哪个Action
4、如果ActionMapper决定调用某个Action,FilterDispatcher把请求的处理交给ActionProxy,这儿已经转到它的Delegate--Dispatcher来执行
5、ActionProxy根据ActionMapping和ConfigurationManager找到需要调用的Action类
6、ActionProxy创建一个ActionInvocation的实例
7、ActionInvocation调用真正的Action,当然这涉及到相关拦截器的调用
8、Action执行完毕,ActionInvocation创建Result并返回,当然,如果要在返回之前做些什么,可以实现PreResultListener。添加PreResultListener可以在Interceptor中实现,不知道其它还有什么方式?

Struts2(2.1.2)部分源码阅读
从org.apache.struts2.dispatcher.FilterDispatcher开始
//创—ispatcher,此类是一个Delegate,它是真正完成根据url解析,读取对应Action的地方


对于其它配置文件只用StrutsXmlConfigurationProvider,此类继承XmlConfigurationProvider,而XmlConfigurationProvider又实现ConfigurationProvider接口。类XmlConfigurationProvider负责配置文件的读取和解析,addAction()方法负责读取<action>标签,并将数据保存在ActionConfig中;addResultTypes()方法负责将<result-type>标签转化为ResultTypeConfig对象;loadInterceptors()方法负责将<interceptor>标签转化为InterceptorConfi对象;loadInterceptorStack()方法负责将<interceptor-ref>标签转化为InterceptorStackConfig对象;loadInterceptorStacks()方法负责将<interceptor-stack>标签转化成InterceptorStackConfig对象。而上面的方法最终会被addPackage()方法调用,将所读取到的数据汇集到PackageConfig对象中。来看XmlConfigurationProvider的源代码,详细的我自己也就大体浏览了一下,各位可以自己研读。

好了,action执行完了,还要根据ResultConfig返回到view,也就是在invoke方法中调用executeResult方法。

最后补充一下,Struts2的查找值和设置值都是使用Ognl来实现的。关于Ognl的介绍可以到其官方网站查看http://www.ognl.org/,我在网上也找到另外一篇http://www.javaeye.com/topic/254684和http://www.javaeye.com/topic/223612。完了来看下面这段小测试程序(其它的Ognl的测试可以自己添加)。
public class TestOgnl {        private User user;    private Map context;        @Before    public void setUp() throws Exception {        }    @Test    public void ognlGetValue() throws Exception {    reset();    Assert.assertEquals("myyate", Ognl.getValue("name", user));    Assert.assertEquals("cares", Ognl.getValue("dept.name", user));    Assert.assertEquals("myyate", Ognl.getValue("name", context, user));    Assert.assertEquals("contextmap", Ognl.getValue("#name", context, user));    Assert.assertEquals("parker", Ognl.getValue("#pen", context, user));    }        @Test    public void ognlSetValue() throws Exception {    reset();    Ognl.setValue("name", user, "myyateC");    Assert.assertEquals("myyateC", Ognl.getValue("name", user));        Ognl.setValue("dept.name", user, "caresC");    Assert.assertEquals("caresC", Ognl.getValue("dept.name", user));        Assert.assertEquals("contextmap", Ognl.getValue("#name", context, user));    Ognl.setValue("#name", context, user, "contextmapC");    Assert.assertEquals("contextmapC", Ognl.getValue("#name", context, user));        Assert.assertEquals("parker", Ognl.getValue("#pen", context, user));    Ognl.setValue("#name", context, user, "parkerC");    Assert.assertEquals("parkerC", Ognl.getValue("#name", context, user));    }        public static void main(String[] args) throws Exception {    JUnitCore.runClasses(TestOgnl.class);    }        private void reset() {    user = new User("myyate", new Dept("cares"));    context = new OgnlContext();    context.put("pen", "parker");    context.put("name", "contextmap");    }}class User {    public User(String name, Dept dept) {    this.name = name;    this.dept = dept;    }    String name;    private Dept dept;    public Dept getDept() {        return dept;    }    public String getName() {        return name;    }    public void setDept(Dept dept) {        this.dept = dept;    }    public void setName(String name) {        this.name = name;    }}class Dept {    public Dept(String name) {    this.name = name;    }    private String name;    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }}

这样,一个Struts2的请求流程基本上就结束了。其实我觉得做项目把Struts2参考文档看两遍就可以了,呵呵!(写博客比看代码还累)

读书人网 >开源软件

热点推荐