struts2请求过程源代码分析

Posted claireyuancy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了struts2请求过程源代码分析相关的知识,希望对你有一定的参考价值。

struts2请求过程源代码分析

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

  我这里的struts2源代码是从官网下载的一个最新的struts-2.3.15.1-src.zip。将其解压就可以。

里面的文件夹页文件很的多,我们仅仅须要定位到struts-2.3.15.1\\src\\core\\src\\main\\java\\org\\apache\\struts2查看源文件。

文件夹结构例如以下图

  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 该包定义与配置相关的接口和类。实际上。project中的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.servlet 用HttpServletRequest相关方法实现principalproxy接口。

org.apache.struts2.util 有用包。
org.apache.struts2.views 提供freemarker、jsp、velocity等不同类型的页面呈现。

 

 根文件夹下的5个文件说明:

StrutsStatics Struts常数。常数能够用来获取或设置对象从行动中或其它集合。
RequestUtils 请求处理程序类。此类仅仅有一个方法getServletPath。作用检索当前请求的servlet路径
ServletActionContext 站点的特定的上下文信息
StrutsConstants 该类提供了框架配置键的中心位置用于存储和检索配置设置。

StrutsException 通用执行时异常类

 

   

 

 

 

struts2 架构图例如以下图所看到的:

按照上图,我们能够看出一个请求在struts的处理大概有例如以下步骤:

  1、client初始化一个指向Servlet容器(比如Tomcat)的请求;

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

  3、接着StrutsPrepareAndExecuteFilter被调用。StrutsPrepareAndExecuteFilter询问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。

 

strut2源代码分析:

  首先我们使用struts2框架都会在web.xml中注冊和映射struts2。配置内容例如以下:

复制代码
1 <filter> 
2     <filter-name>struts2</filter-name>  
3     <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class> 
4   </filter>  
5   <filter-mapping> 
6     <filter-name>struts2</filter-name>  
7     <url-pattern>/*</url-pattern> 
8   </filter-mapping>
复制代码

注:在早期的struts2中。都是使用FilterDispathcer。从Struts 2.1.3開始,它已不推荐使用。假设你使用的Struts的版本号 >= 2.1.3,推荐升级到新的Filter,StrutsPrepareAndExecuteFilter。

在此研究的是StrutsPrepareAndExecuteFilter。

  StrutsPrepareAndExecuteFilter中的方法:

void init(FilterConfig filterConfig)  继承自Filter,过滤器的初始化
doFilter(ServletRequest req, ServletResponse res, FilterChain chain)  继承自Filter。运行过滤器
void destroy() 继承自Filter,用于资源释放
void postInit(Dispatcher dispatcher, FilterConfig filterConfig)  Callback for post initialization(一个空的方法,用于方法回调初始化)

 web容器一启动,就会初始化核心过滤器StrutsPrepareAndExecuteFilter。并运行初始化方法,初始化方法例如以下:

复制代码
 1 public void init(FilterConfig filterConfig) throws ServletException {
 2         InitOperations init = new InitOperations();
 3         Dispatcher dispatcher = null;
 4         try {
 5             //封装filterConfig。当中有个主要方法getInitParameterNames将參数名字以String格式存储在List中
 6             FilterHostConfig config = new FilterHostConfig(filterConfig);
 7             //初始化struts内部日志
 8             init.initLogging(config);
 9             //创建dispatcher ,并初始化
10             dispatcher = init.initDispatcher(config);
11             init.initStaticContentLoader(config, dispatcher);
12             //初始化类属性:prepare 、execute
13             prepare = new PrepareOperations(filterConfig.getServletContext(), dispatcher);
14             execute = new ExecuteOperations(filterConfig.getServletContext(), dispatcher);
15             this.excludedPatterns = init.buildExcludedPatternsList(dispatcher);
16             //回调空的postInit方法
17             postInit(dispatcher, filterConfig);
18         } finally {
19             if (dispatcher != null) {
20                 dispatcher.cleanUpAfterInit();
21             }
22             init.cleanup();
23         }
24     }
复制代码

 关于封装filterConfig,首先看下FilterHostConfig ,源代码例如以下:

复制代码
 1 public class FilterHostConfig implements HostConfig {
 2 
 3     private FilterConfig config;
 4     //构造方法
 5     public FilterHostConfig(FilterConfig config) {
 6         this.config = config;
 7     }
 8     //依据init-param配置的param-name获取param-value的值  
 9     public String getInitParameter(String key) {
10         return config.getInitParameter(key);
11     }
12     //返回初始化參数名的迭代器 
13     public Iterator<String> getInitParameterNames() {
14         return MakeIterator.convert(config.getInitParameterNames());
15     }
16     //返回Servlet上下文
17     public ServletContext getServletContext() {
18         return config.getServletContext();
19     }
20 }
复制代码

  仅仅有短短的几行代码,getInitParameterNames是这个类的核心,将Filter初始化參数名称有枚举类型转为Iterator。此类的主要作为是对filterConfig 封装。

  接下来,看下StrutsPrepareAndExecuteFilter中init方法中dispatcher = init.initDispatcher(config);这是初始化dispatcher的,是通过init对象的initDispatcher方法来初始化的,init是InitOperations类的对象,我们看看InitOperations中initDispatcher方法:

1  public Dispatcher initDispatcher( HostConfig filterConfig ) {
2         Dispatcher dispatcher = createDispatcher(filterConfig);
3         dispatcher.init();
4         return dispatcher;
5     }

  创建Dispatcher。会读取 filterConfig 中的配置信息,将配置信息解析出来。封装成为一个Map,然后根绝servlet上下文和參数Map构造Dispatcher :

复制代码
 1 private Dispatcher createDispatcher( HostConfig filterConfig ) {
 2         //存放參数的Map
 3         Map<String, String> params = new HashMap<String, String>();
 4         //将參数存放到Map
 5         for ( Iterator e = filterConfig.getInitParameterNames(); e.hasNext(); ) {
 6             String name = (String) e.next();
 7             String value = filterConfig.getInitParameter(name);
 8             params.put(name, value);
 9         }
10         //依据servlet上下文和參数Map构造Dispatcher 
11         return new Dispatcher(filterConfig.getServletContext(), params);
12     }
复制代码

  这样dispatcher对象创建完毕,接着就是dispatcher对象的初始化,打开Dispatcher类。看到它的init方法例如以下: