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方法例如以下: