牛骨文教育服务平台(让学习变的简单)
博文笔记

Struts 2详细工作流程及原理

创建时间:2015-09-08 投稿人: 浏览次数:7220
 

Struts 2详细工作流程

    

Struts2工作原理及流程

     Struts2框架的基本思想是采用MVC设计模式,即将应用设计成模型(Model)、视图(View)和控制器(Control)三个部分;

     那么Struts2框架中是如何实现MVC模式的呢?控制部分由DispatchFilter承担,模型部分是由一系列的拦截器(Interceptors)、Action组件和ActionContext组件组成,视图组件则是由Result组件组成;

那么Struts2框架是怎么工作的呢?

     如当我们在浏览器的地址栏中输入:http://localhost:8080/Struts/TestMvc/add.action,浏览器就会把这个请求发送给tomcat,tomcat接收到这个请求后,会检查一下应该交给哪个web程序处理,现在是交给Struts去处理,然后Struts会去参考此程序下的配置文件web.xml,在web.xml中找到过滤器(Filter),如(ActionContextCleanUp、其他过滤器(SiteMesh等)、 FilterDispatcher),注意这里是有顺序的,先ActionContextCleanUp,再其他过滤器(SiteMesh等)、最后到FilterDispatcher;

     FilterDispatcher是控制器的核心,就是mvc中c控制层的核心,FilterDispatcher进行初始化并启用核心 doFilter。FilterDispatcher询问ActionMapper来决定这个请是否需要调用某个Action, 如果 ActionMapper决定需要调用某个Action,FilterDispatcher把请求的处理交给 ActionProxy ,ActionProxy通过struts.xml询问框架的配置文件,找到需要调用的Action类和方法来处理这请求;

    Action执行完毕,根据struts.xml中的配置找到对应的返回结果result,并跳转到相应页面,最后返回HTTP响应到客户端浏览器;

 

  其实用最简单的七个步骤:

  1:客户端在浏览器中输入一个url地址;

  2:这个url请求通过http协议发送给tomcat;

  3:tomcat根据url找到对应项目里面的web.xml文件;

  4:在web.xml里面会发现有struts2的配置;

  5:然后会找到struts2对应的struts.xml配置文件;

  6:根据url解析struts.xml配置文件就会找到对应的class;

  7:调用完class返回一个结果result,根据struts.xml返回到对应的jsp;


Struts2框架由三部分构成:核心控制器、业务控制器和用户实现的业务逻辑组件。在这三部分中,struts2框架提供了核心控制器StrutsPrepareAndExecuteFilter,而用户需要实现业务控制层和业务逻辑层。

一、核心控制器 StrutsPrepareAndExecuteFilter

 StrutsPrepareAndExecuteFilter与struts2以前版本中的FilterDispatcher一样。它是struts2框架的核心控制器,该控制器作为一个Filter运行在web应用中,它负责拦截所有的用户请求,当用户请求到达时,该Filter会过滤用户请求,如果用户请求以action结尾,该请求就会被转入struts2框架来处理。

Struts2框架获取*.action请求后,将根据*.action请求的前面部分决定调用那个业务逻辑组件,例如:对于login.action请求,Struts2调用名为login的Action来处理该请求。

Struts2用户处理请求的Action实例,并不是用户实现的业务控制器,而是Action代理--因为用户实现的业务控制器并没有与ServletAPI耦合,显示无法处理用户请求,而struts2框架提供了系列拦截器,该系列拦截器负责将HttpServletRequest请求中的桉树解析出来,传入Action中,并huidiaoAction的execute方法来处理用户请求。

上面的处理过程是典型的AOP(面向切面编程)处理方式,如图所示的处理模型:

从图看出,用户实现的Action仅仅是struts2的Action代理的代理目标,用户实现的业务控制器Action则包含了对用户请求的处理,用户的请求数据包含在HttpServletRequest对象中, 而用户Action类无需访问HttpServletRequest对象,拦截器会将请求数据解析出来并传给业务逻辑组件Action实例

二、业务控制器

简述:左右项目开发中action控制层,用户接受数据,封装数据,调用业务逻辑层

业务控制器组件就是用户Action类的实例,Action类通常包含了一个excute方法,该方法返回一个字符串-----该字符串就是一个逻辑视图名,当业务控制器处理完用户请求后,根据处理结果不同,excute方法返回不同字符串。

每个字符串对应一个视图名

在写完控业务制器后,需要配置Action的如下三个部分定义

●Action所处理的URL

●Action组件所对应的实现类

●Action里包含的逻辑视图和物理资源之间的对应关系

每个Action都要处理一个用户请求,而用户请求总是包含了指定URL,当StrutsPrepareAndExecuteFilter拦截到用户请求后,根据请求的URL和Action处理URL之间的对应关系来处理转发

三、struts2的模型组件

Java EE 应用里的模型组件,通常指系统的业务逻辑组件,而隐藏在系统逻辑组件下面的,可能还包含了DAO,领域对象等组件。

MVC框架里的业务控制器会调用模型组件的方法来处理用户请求,也就是说,业务控制器不会对用户请求进行实际处理,用户请求最终由模型组件负责处理,业务控制器只是中间负责调度器,这也是称Action为控制器的原因

四、Struts2的视图组件

Struts2已经改变了struts1只能使用JSP作为视图技术的现状,允许使用其他模版技术。

当struts2的控制器返回逻辑视图名时,逻辑视图并未与任何的视图技术关联,仅仅是返回一个字符串,该字符串作为逻辑视图名。

当我们在struts.xml文件中配置Action时,要为Action元素指定系列result子元素,每个result子元素定义一个逻辑视图和物理视图之间的映射,如果没有指定type属性,默认使用JSP左右视图资源。也可以指定很多类型 chain 转发到指定action中,redircter,重定向。

五、运行流程

Struts2框架的运行流程非常相似于WebWork框架的流程,struts2其实就是WebWork2.2的升级版,因此,struts2的运行流程与WebWork运行流程完全相同,如图WebWork的运行流程:

当用户向Web应用发送请求时,该请求经过ActionContextCleanUp、SiteMesh等过滤器过滤。由WebWork的核心控制器拦截,如果用户请求需要WebWWork的业务逻辑控制器处理,该控制器则调用Action映射器,该映射器将用户请求转发到对应的业务逻辑控制器。值得注意的是,测试的业务逻辑控制器并不是开发者实现的控制器,而是WebWork创建的控制器代理,创建控制器代理时,WebWork需要得到开着定义的xwork,xml配置文件,控制器代理以用户实现的控制器作为目标,以拦截器链中的拦截器作为处理。

业务逻辑控制器只是WebWork控制器的目标-----这就是为什么开发者自己实现的Action可以与servletAPI分离的原因,当Action处理完HTTP请求后,该结果只是一个普通的字符串,该字符串将对应到指定的视图资源。 指定的视图资源经过拦截器链处理后,生成对客户端的响应输出


Struts2是Struts社区和WebWork社区的共同成果,我们甚至可以说,Struts2是WebWork的升级版,他采用的正是WebWork的核心,所以,Struts2并不是一个不成熟的产品,相反,构建在WebWork基础之上的Struts2是一个运行稳定、性能优异、设计成熟的WEB框架。

本章主要对Struts的源代码进行分析,因为Struts2与WebWork的关系如此密不可分,因此,读者需要下载xwork的源代码,访问http://www.opensymphony.com/xwork/download.action即可自行下载。

下载的Struts2源代码文件是一个名叫struts-2.1.0-src.zip的压缩包,里面的目录和文件非常多,读者可以定位到struts-2.1.0-src"struts-2.0.10"src"core"src"main"java目录下查看Struts2的源文件,如图14所示。

 

(图14)

主要的包和类

Struts2框架的正常运行,除了占核心地位的xwork的支持以外,Struts2本身也提供了许多类,这些类被分门别类组织到不同的包中。从源代码中发现,基本上每一个Struts2类都访问了WebWork提供的功能,从而也可以看出Struts2与WebWork千丝万缕的联系。但无论如何,Struts2的核心功能比如将请求委托给哪个Action处理都是由xwork完成的,Struts2只是在WebWork的基础上做了适当的简化、加强和封装,并少量保留Struts1.x中的习惯。

以下是对各包的简要说明:

包名

说明

org.apache.struts2. components

该包封装视图组件,Struts2在视图组件上有了很大加强,不仅增加了组件的属性个数,更新增了几个非常有用的组件,如updownselect、doubleselect、datetimepicker、token、tree等。

另外,Struts2可视化视图组件开始支持主题(theme),缺省情况下,使用自带的缺省主题,如果要自定义页面效果,需要将组件的theme属性设置为simple。

org.apache.struts2. config

该包定义与配置相关的接口和类。实际上,工程中的xml和properties文件的读取和解析都是由WebWork完成的,Struts只做了少量的工作。

org.apache.struts2.dispatcher

Struts2的核心包,最重要的类都放在该包中。

org.apache.struts2.impl

该包只定义了3个类,他们是StrutsActionProxy、StrutsActionProxyFactory、StrutsObjectFactory,这三个类都是对xwork的扩展。

org.apache.struts2.interceptor

定义内置的截拦器。

org.apache.struts2.util

实用包。

org.apache.struts2.validators

只定义了一个类:DWRValidator。

org.apache.struts2.views

提供freemarker、jsp、velocity等不同类型的页面呈现。

下表是对一些重要类的说明:

类名

说明

org.apache.struts2.dispatcher. Dispatcher

      该类有两个作用:

       1、初始化

       2、调用指定的Action的execute()方法。

org.apache.struts2.dispatcher. FilterDispatcher

      这是一个过滤器。文档中已明确说明,如果没有经验,配置时请将url-pattern的值设成/*。

      该类有四个作用:

       1、执行Action

       2、清理ActionContext,避免内存泄漏

       3、处理静态内容(Serving static content)

       4、为请求启动xwork’s的截拦器链。

com.opensymphony.xwork2. ActionProxy

       Action的代理接口。

com.opensymphony.xwork2. ctionProxyFactory

      生产ActionProxy的工厂。

com.opensymphony.xwork2.ActionInvocation

      负责调用Action和截拦器。

com.opensymphony.xwork2.config.providers. XmlConfigurationProvider

      负责Struts2的配置文件的解析。

Struts2的工作机制

3.1Struts2体系结构图

       Strut2的体系结构如图15所示:

 

      (图15)

3.2Struts2的工作机制

      从图15可以看出,一个请求在Struts2框架中的处理大概分为以下几个步骤:

1、客户端初始化一个指向Servlet容器(例如Tomcat)的请求;

2、这个请求经过一系列的过滤器(Filter)(这些过滤器中有一个叫做ActionContextCleanUp的可选过滤器,这个过滤器对于Struts2和其他框架的集成很有帮助,例如:SiteMesh Plugin);

3、接着FilterDispatcher被调用,FilterDispatcher询问ActionMapper来决定这个请求是否需要调用某个Action;

4、如果ActionMapper决定需要调用某个Action,FilterDispatcher把请求的处理交给ActionProxy;

5、ActionProxy通过Configuration Manager询问框架的配置文件,找到需要调用的Action类;

6、ActionProxy创建一个ActionInvocation的实例。

7、ActionInvocation实例使用命名模式来调用,在调用Action的过程前后,涉及到相关拦截器(Intercepter)的调用。

8、一旦Action执行完毕,ActionInvocation负责根据struts.xml中的配置找到对应的返回结果。返回结果通常是(但不总是,也可能是另外的一个Action链)一个需要被表示的JSP或者FreeMarker的模版。在表示的过程中可以使用Struts2框架中继承的标签。在这个过程中需要涉及到ActionMapper。

注:以上步骤参考至网上,具体网址已忘记。在此表示感谢!

3.3Struts2源代码分析

      和Struts1.x不同,Struts2的启动是通过FilterDispatcher过滤器实现的。下面是该过滤器在web.xml文件中的配置:

代码清单6:web.xml(截取)

   <filter>

      <filter-name>struts2</filter-name>

      <filter-class>

           org.apache.struts2.dispatcher.FilterDispatcher

      </filter-class>

   </filter>

   <filter-mapping>

      <filter-name>struts2</filter-name>

      <url-pattern>/*</url-pattern>

   </filter-mapping>

       Struts2建议,在对Struts2的配置尚不熟悉的情况下,将url-pattern配置为/*,这样该过滤器将截拦所有请求。

      实际上,FilterDispatcher除了实现Filter接口以外,还实现了StrutsStatics接口,继承代码如下:

代码清单7:FilterDispatcher结构

publicclassFilterDispatcherimplementsStrutsStatics, Filter {

}

StrutsStatics并没有定义业务方法,只定义了若干个常量。Struts2对常用的接口进行了重新封装,比如HttpServletRequest、HttpServletResponse、HttpServletContext等。 以下是StrutsStatics的定义:

代码清单8:StrutsStatics.java

publicinterfaceStrutsStatics {

   /**

    *ConstantfortheHTTPrequestobject.

    */

   publicstaticfinalStringHTTP_REQUEST="com.opensymphony.xwork2.dispatcher.HttpServletRequest";

   /**

    *ConstantfortheHTTPresponseobject.

    */

   publicstaticfinalStringHTTP_RESPONSE="com.opensymphony.xwork2.dispatcher.HttpServletResponse";

   /**

    *ConstantforanHTTPrequest dispatcher}.

    */

   publicstaticfinalStringSERVLET_DISPATCHER="com.opensymphony.xwork2.dispatcher.ServletDispatcher";

   /**

    *Constantfortheservlet context}object.

    */

   publicstaticfinalStringSERVLET_CONTEXT="com.opensymphony.xwork2.dispatcher.ServletContext";

   /**

    *ConstantfortheJSPpage context}.

    */

publicstaticfinalStringPAGE_CONTEXT="com.opensymphony.xwork2.dispatcher.PageContext";

   /**ConstantforthePortletContextobject*/

   publicstaticfinalStringSTRUTS_PORTLET_CONTEXT="struts.portlet.context";

}

   容器启动后,FilterDispatcher被实例化,调用init(FilterConfig filterConfig)方法。该方法创建Dispatcher类的对象,并且将FilterDispatcher配置的初始化参数传到对象中(详情请参考代码清单10),并负责Action的执行。然后得到参数packages,值得注意的是,还有另外三个固定的包和该参数进行拼接,分别是org.apache.struts2.static、template、和org.apache.struts2.interceptor.debugging,中间用空格隔开,经过解析将包名变成路径后存储到一个名叫pathPrefixes的数组中,这些目录中的文件会被自动搜寻。

代码清单9:FilterDispatcher.init()方法

   publicvoidinit(FilterConfig filterConfig)throwsServletException {

       this.filterConfig = filterConfig;      

       dispatcher = createDispatcher(filterConfig);

       dispatcher.init();      

       String param = filterConfig.getInitParameter("packages");

       String packages ="org.apache.struts2.static template org.apache.struts2.interceptor.debugging";

       if(param !=null) {

            packages = param +" "+ packages;

       }

       this.pathPrefixes= parse(packages);

}

代码清单10:FilterDispatcher.createDispatcher()方法

   protectedDispatcher createDispatcher(FilterConfig filterConfig) {

       Map<String,String> params =newHashMap<String,String>();

       for(Enumeration e = filterConfig.getInitParameterNames(); e.hasMoreElements(); ) {

           String name = (String) e.nextElement();

           String value = filterConfig.getInitParameter(name);

           params.put(name, value);

       }

       returnnewDispatcher(filterConfig.getServletContext(), params);

   }

   当用户向Struts2发送请求时,FilterDispatcher的doFilter()方法自动调用,这个方法非常关键。首先,Struts2对请求对象进行重新包装,此次包装根据请求内容的类型不同,返回不同的对象,如果为multipart/form-data类型,则返回MultiPartRequestWrapper类型的对象,该对象服务于文件上传,否则返回StrutsRequestWrapper类型的对象,MultiPartRequestWrapper是StrutsRequestWrapper的子类,而这两个类都是HttpServletRequest接口的实现。包装请求对象如代码清单11所示:


 Struts 2框架本身大致可以分为3个部分:核心控制器FilterDispatcher、业务控制器Action和用户实现的企业业务逻辑组件。

3.1.1  核心控制器FilterDispatcher

 

核心控制器FilterDispatcher是Struts 2框架的基础,包含了框架内部的控制流程和处理机制。业务控制器Action和业务逻辑组件是需要用户来自己实现的。用户在开发Action和业务逻辑组件的同时,还需要编写相关的配置文件,供核心控制器FilterDispatcher来使用。

Struts 2的工作流程相对于Struts 1要简单,与WebWork框架基本相同,所以说Struts 2是WebWork的升级版本。Struts 2框架按照模块来划分,可以分为Servlet Filters、Struts核心模块、拦截器和用户实现部分。Struts 2框架结构图如图3.1所示。

图3.1  Struts 2框架结构图

一个请求在Struts 2框架中的处理大概分为以下几个步骤。

 客户端提交一个(HttpServletRequest)请求,如上文在浏览器中输入http://localhost: 8080/bookcode/ch2/Reg.action就是提交一个(HttpServletRequest)请求。

 请求被提交到一系列(主要是3层)的过滤器(Filter),如(ActionContextCleanUp、其他过滤器(SiteMesh等)、FilterDispatcher)。注意:这里是有顺序的,先ActionContext CleanUp,再其他过滤器(Othter Filters、SiteMesh等),最后到FilterDispatcher。

  FilterDispatcher是控制器的核心,就是MVC的Struts 2实现中控制层(Controller)的核心。

  FilterDispatcher询问ActionMapper是否需要调用某个Action来处理这个(HttpServlet Request)请求,如果ActionMapper决定需要调用某个Action,FilterDispatcher则把请求的处理交给ActionProxy。

  ActionProxy通过Configuration Manager(struts.xml)询问框架的配置文件,找到需要调用的Action类。例如,用户注册示例将找到UserReg类。

  ActionProxy创建一个ActionInvocation实例,同时ActionInvocation通过代理模式调用Action。但在调用之前,ActionInvocation会根据配置加载Action相关的所有Interceptor(拦截器)。

 一旦Action执行完毕,ActionInvocation负责根据struts.xml中的配置找到对应的返回结果result。

Struts 2的核心控制器是FilterDispatcher,有3个重要的方法:destroy()、doFilter()和Init(),可以在Struts 2的下载文件夹中找到源代码,如代码3.1所示。

代码3.1  核心控制器FilterDispatcher

 

public class FilterDispatcher implements StrutsStatics, Filter {

    /**

     * 定义一个Log实例

     */

private static final Log LOG = LogFactory.getLog(FilterDispatcher.class);

… ...

    /**

     * 存放属性文件中的.STRUTS_I18N_ENCODING值

     */

    private static String encoding;

    /**

     * 定义ActionMapper实例

     */

    private static ActionMapper actionMapper;

    /**

     * 定义FilterConfig实例

     */

    private FilterConfig filterConfig;

    protected Dispatcher dispatcher;

    /**

     * 创建一个默认的dispatcher,初始化filter

     * 设置默认的packages     *

     */

    public void init(FilterConfig filterConfig) throws ServletException {

     this.filterConfig = filterConfig;

       dispatcher = createDispatcher(filterConfig);

        dispatcher.init();

        String param = filterConfig.getInitParameter("packages");

        String packages = "org.apache.struts2.static template org.apache.struts2.interceptor.debugging";

        if (param != null) {

            packages = param + " " + packages;

        }

        this.pathPrefixes = parse(packages);

    }

    //销毁filter方法

   public void destroy() {

        if (dispatcher == null) {

            LOG.warn("something is seriously wrong, Dispatcher is not initialized (null) ");

        } else {

            dispatcher.cleanup();

        }

    }

    /**

     * 处理一个Action或者资源请求

     * <p/>

     * filter尝试将请求同action mapping相匹配

     * 如果找到,将执行dispatcher的serviceAction方法

     * 如果Action处理失败, doFilter将建立一个异常

     * <p/>

     * 如果请求静态资源

     * 资源将被直接复制给 response

     * <p/>

     * 如果找不到匹配Action 或者静态资源,则直接跳出

     public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;

声明:该文观点仅代表作者本人,牛骨文系教育信息发布平台,牛骨文仅提供信息存储空间服务。