Struts 2 工作原理

时间向前,技术也在不断更新中,有时间我来复习一下Struts 2 的工作原理。

Struts 2初始化过程:

struts2的启动入口为

org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter

 struts2的启动就是执行它的init()方法。我觉得它的启动就是为了一个目的,那就是为了创建出Container对象和Packageconfig对象。其中Container为容器提供IoC机制,而Packageconfig则为后来的由用户实现的Action提供映射内容。

Struts 2处理请求过程:

当Struts收到由Web容器转发过来的请求(HttpServletRequest)时,它首先将请求传递给一个标准的的过滤链包括(ActionContextCleanUp)过滤器,然后经过一系列Struts默认提供的Filters(SiteMesh ,etc),接下来需要调用StrutsPrepareAndExecuteFilter核心控制器,然后它调用ActionMapper确定请求那个Action,ActionMapper返回一个收集Action详细信息的ActionMaping对象。

接下来StrutsPrepareAndExecuteFilter将控制权委派给ActionProxy,ActionProxy调用配置管理器(ConfigurationManager) 从配置文件中读取配置信息(struts.xml),然后创建ActionInvocation对象,ActionInvocation在调用Action之前会依次的调用所用配置拦截器(Interceptor N) 一旦执行结果返回结果字符串ActionInvocation负责查找结果字符串对应的(Result)然后执行这个Result Result会调用一些模版(JSP)来呈现页面,之后拦截器(Interceptor N)会在被执行(顺序和Action执行之前相反)最后响应(HttpServletResponse)被返回在web.xml中配置的那些过滤器和(核心控制器)(StrutsPrepareAndExecuteFilter)。

  1. 客户端提起一个(HttpServletRequest)请求,如在浏览器中输入”http://localhost:8080/addXXX.action”。
  2. 请求被提交到一系列(主要是三层)的过滤器(Filter),如(ActionContextCleanUp、其他过滤器 (SiteMesh等)、 FilterDispatcher)。注意这里是有顺序的,先ActionContextCleanUp,再其他过滤器(SiteMesh等)、最后到 FilterDispatcher。
  3. FilterDispatcher是控制器的核心,就是mvc中c控制层的核心。FilterDispatcher进行初始化并启用核心doFilter,FilterDispatcher询问ActionMapper是否需要调用某个Action来处理这个(request)请求,如果ActionMapper决定需要调用某个Action,FilterDispatcher把请求的处理交给ActionProxy
  4. ActionProxy通过Configuration Manager(struts.xml)询问框架的配置文件,找到需要调用的Action类.
  5. ActionProxy创建一个ActionInvocation的实例,同时ActionInvocation通过代理模式调用Action。但在调用 之前ActionInvocation会根据配置加载Action相关的所有Interceptor。(Interceptor是struts2另一个核心概念)
    ActionInvocation 是Xworks 中Action 调度的核心。而对Interceptor 的调度,也正是由ActionInvocation负责。ActionInvocation 是一个接口, 而DefaultActionInvocation 则是Webwork 对ActionInvocation的默认实现。
    Interceptor 的调度流程大致如下:
    a. ActionInvocation初始化时,根据配置,加载Action相关的所有Interceptor。
    b. 通过ActionInvocation.invoke方法调用Action实现时,执行Interceptor。
    Interceptor 将很多功能从我们的Action中独立出来,大量减少了我们Action的代码,独立出来的行为具有很好的重用性。XWork、WebWork的许多功能都是用Interceptor实现,可以在配置文件中组装Action用到的Interceptor,它会按照你指定的顺序,在Action执行前后运行。
    么什么是拦截器。
    拦截器就是AOP(Aspect-Oriented Programming)的一种实现。(AOP是指用于在某个方法或字段被访问之前,进行拦截然后在之前或之后加入某些操作。)
  6. 一旦Action执行完毕,ActionInvocation负责根据struts.xml中的配置找到对应的返回结果。如果返回的是另外一个action,那么重复上面的流程一遍。

解释流程一张图足矣:
 

 

基类

Struts 2的Action无须实现任何接口或继承任何类型,普通的POJO类就可以用做Action类,但是,我们为了方便实现Action,大多数情况下都会继承com.opensymphony.xwork2.ActionSupport类,并重载(Override)此类里的String execute()方法,因为ActionSupport已经实现了Action接口,还实现了Validateable接口,提供了数据校验功能。当我们在写action的时候,可以实现Action接口,也可以继承Actionsupport这个类.这两个有什么区别呢? 

扫描二维码关注公众号,回复: 619517 查看本文章

Action接口有: 

public static final java.lang.String SUCCESS = "success"; 
public static final java.lang.String NONE = "none"; 
public static final java.lang.String ERROR = "error"; 
public static final java.lang.String INPUT = "input"; 
public static final java.lang.String LOGIN = "login"; 
public abstract java.lang.String execute() throws java.lang.Exception; 

而Actionsupport这个工具类在实现了Action接口的基础上还定义了一个validate()方法,重写该方法,它会在execute()方法之前执行,如校验失败,会转入input处,必须在配置该Action时配置input属性。 

Actionsupport提供了一个getText(String key)方法还实现国际化,该方法从资源文件上获取国际化信息. 这样在自定义标签时可以定义一个变量为new actionsupport对象实现国际化。

另外,ActionSupport还提供了

addActionMessage(String aMessage);

addFieldError(String fieldName, String errorMessage);//校验失败后返回给客户端的信息,struts2 标签<s:fielderror />可以取得

addActionError(String anErrorMessage);

ActionSupport类的作用 :

struts2不要求我们自己设计的action类继承任何的struts基类或struts接口,但是我们为了方便实现我们自己的action,大多数情况下都会继承com.opensymphony.xwork2.ActionSupport类,并重写此类里的public String execute() throws Exception方法。因为此类中实现了很多的实用借口,提供了很多默认方法,这些默认方法包括国际化信息的方法、默认的处理用户请求的方法等,这样可以大大的简化Acion的开发。 

Struts2中通常直接使用Action来封装HTTP请求参数,因此,Action类里还应该包含与请求参数对应的属性,并且为属性提供对应的getter和setter方法。

Redirect Chains

承载类:com.opensymphony.xwork2.ActionChainResult

chain其实只是在一个action执行完毕之后,forward到另外一个action,所以他们之间是共享HttpServletRequest的。在使用chain作为Result时,往往会配合使用ChainingInterceptor。ChainingInterceptor的作用是在Action直接传递数据。事实上,源Action中ValueStack的数据会被做一次Copy,这样,2个Action中的数据都在ValueStack中,使得对于前台来说,通过ValueStack来取数据,是透明而共享的。比如说,一张页面中,你可能有许多数据要显示,而某些数据的获取方式可能被很多不同的页面共享(典型来说,“推荐文章”这个小栏目的数据获取,可能会被很多页面所共享)。这种情况下,可以把这部分逻辑抽取到一个独立Action中,并使用chain,将这个Action与主Action串联起来。这样,最后到达页面的时候,页面始终可以得到每个Action中的数据。

从实战上讲,使用chain作为Result也的确存在着上面所说的许多问题,我个人也是非常不推崇滥用这种Result。尤其是,对于使用Spring和Hibernate的朋友来说,如果你开启OpenSessionInView模式,那么Hibernate的session是跟随HttpServletRequest的,所以session在整个action链中共享。这会为我们的编程带来极大的麻烦。因为我们知道Hibernate的session会保留一份一级缓存,在action链中,共享一级缓存无疑会为你的调试工作带来很大的不方便。

所以,谨慎使用chain作为你的Result,应该成为一条最佳实践。

与Struts1的区别

猜你喜欢

转载自linbaolee.iteye.com/blog/2084038