- 浏览: 15808 次
文章分类
最新评论
1. Struts2架构图
请求首先通过Filter chain,Filter主要包括ActionContextCleanUp,它主要清理当前线程的ActionContext和Dispatcher;
FilterDispatcher主要通过AcionMapper来决定需要调用哪个Action。
ActionMapper取得了ActionMapping后,在Dispatcher的serviceAction方法里创建ActionProxy,ActionProxy创建ActionInvocation,然后ActionInvocation调用Interceptors,执行Action本身,创建Result并返回。
当然,如果要在返回之前做些什么,可以实现PreResultListener,这个PreResultListener只能执行一次。
2. Struts2部分类介绍 ActionProxy&ActionInvocation 3. Struts2请求流程 4. ActionContext ActionContext包括了很多信息,比如Session、Application、Request、Locale、ValueStack等。其中ValueStack可以解析ognl表达式,来动态后去一些值,同时可以给表达式提供对象。 ActionContext(com.opensymphony.xwork.ActionContext)是Action执行时的上下文,上下文可以看作是一个容器 (其实我们这里的容器就是一个Map而已),它存放的是Action在执行时需要用到的对象. ActionContext context = (ActionContext) actionContext.get(); 来获取的. 我们再来看看这里的actionContext对象的创建: static ThreadLocal actionContext = new ActionContextThreadLocal(); ActionContextThreadLocal是实现ThreadLocal的一个内部类. 通过ActionContext取得HttpSession: Map session = ActionContext.getContext().getSession(); (通过Map模拟HttpServlet的对象,操作更方便)。 5. ServletActionContext 如何从ServletActionContext里取得Servlet的相关对象: 6. ServletActionContext和ActionContext联系 注意:在使用ActionContext时有一点要注意: 不要在Action的构造函数里使用ActionContext.getContext(), 因为这个时候ActionContext里的一些值也许没有设置,这时通过ActionContext取得的值也许是null;
这部分从Struts2参考文档中翻译就可以了。
ActionMapper
ActionMapper其实是HttpServletRequest和Action调用请求的一个映射,它屏蔽了Action对于Request等Servlet类的依赖。Struts2中它的默认实现类是DefaultActionMapper,ActionMapper很大的用处可以根据自己的需要来设计url格式,它自己也有Restful的实现,具体可以参考文档的docs\actionmapper.html。
Action的一个代理,由ActionProxyFactory创建,它本身不包括Action实例,
默认实现DefaultActionProxy是由ActionInvocation持有Action实例。
ActionProxy作用是如何取得Action,无论是本地还是远程。而ActionInvocation的作用是如何执行Action,拦截器的功能就是在ActionInvocation中实现的。
ConfigurationProvider&Configuration
ConfigurationProvider就是Struts2中配置文件的解析器,
Struts2中的配置文件主要是通过实现类XmlConfigurationProvider及其子类StrutsXmlConfigurationProvider来解析。
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中实现。
ActionContext是被存放在当前线程中的,获取ActionContext也是从ThreadLocal中获取的。
所以在执行拦截器、action和result的过程中,由于他们都是在一个线程中按照顺序执行的,所以可以在任意时候在ThreadLocal中获取ActionContext。
一般情况, 我们的ActionContext都是通过:
ThreadLocal可以命名为"线程局部变量",它为每一个使用该变量的线程都提供一个变量值的副本,使每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突.
这样,我们 ActionContext里的属性只会在对应的当前请求线程中可见,从而保证它是线程安全的.
ServletActionContext(com.opensymphony.webwork. ServletActionContext),这个类直接继承了我们上面介绍的ActionContext,它提供了直接与Servlet相关对象访问的功能,它可以取得的对象有:
(1)javax.servlet.http.HttpServletRequest : HTTPservlet请求对象
(2)javax.servlet.http.HttpServletResponse : HTTPservlet相应对象
(3)javax.servlet.ServletContext : Servlet上下文信息
(4)javax.servlet.ServletConfig : Servlet配置对象
(5)javax.servlet.jsp.PageContext : Http页面上下文
<1>取得HttpServletRequest对象: HttpServletRequest request = ServletActionContext. getRequest();
<2>取得HttpSession对象: HttpSession session = ServletActionContext. getRequest().getSession();
ServletActionContext和ActionContext有着一些重复的功能。
我们遵循的原则是:如果ActionContext能够实现我们的功能,那最好就不要使用ServletActionContext,让我们的Action尽量不要直接去访问Servlet的相关对象.
同样,HttpServletRequest req = ServletActionContext.getRequest()也不要放在构造函数中,也不要直接将req作为类变量给其赋值。
至于原因,我想是因为前面讲到的static ThreadLocal actionContext = new ActionContextThreadLocal(),
从这里我们可以看出ActionContext是线程安全的,而 ServletActionContext继承自ActionContext,所以ServletActionContext也线程安全,
线程安全要求每个线程都独立进行,所以req的创建也要求独立进行,所以ServletActionContext.getRequest()这句话不要放在构造函数中,也不要直接放在类中,而应该放在每个具体的方法体中(eg:login()、queryAll()、insert()等),这样才能保证每次产生对象时独立的建立了一个req。
7.ActionContextClearUp
ActionContextClearUp其实是Defer ClearUP.作用就是延长action中属性的生命周期,
包括自定义属性,以便在jsp页面中进行访问,让actionContextcleanup过滤器来清除属性,不让action自己清除。具体看下面的代码,代码很简单:
- <SPAN style="FONT-SIZE: small">public void doFilter(...){
- ...
- try{
- ...
- //继续执行所配置的chain中的Filter
- chain.doFilter(request, response);
- }finally{
- //保证在所有动作执行完之后,调用cleanUp
- ...
- cleanUp(request);
- }
- }
- protected static void cleanUp(ServletRequest req) {
- ...
- ActionContext.setContext(null);//清除ActionContext实例
- Dispatcher.setInstance(null);//清除Dispatcher实例(Dispatcher主要是完成将url解析成对应的Action)
- }
- </SPAN>
public void doFilter(...){ ... try{ ... //继续执行所配置的chain中的Filter chain.doFilter(request, response); }finally{ //保证在所有动作执行完之后,调用cleanUp ... cleanUp(request); } } protected static void cleanUp(ServletRequest req) { ... ActionContext.setContext(null);//清除ActionContext实例 Dispatcher.setInstance(null);//清除Dispatcher实例(Dispatcher主要是完成将url解析成对应的Action) }
另外注明一下UtilTimerStack的push和pop是用来计算调用方法所执行的开始和结束时间,用来做性能测试的。在struts的源码中随处可见。用法如下:
- <SPAN style="FONT-SIZE: small">String timerKey = "ActionContextCleanUp_doFilter: ";
- UtilTimerStack.setActive(true);
- UtilTimerStack.push(timerKey);
- //调用要测试的方法。
- UtilTimerStack.pop(timerKey);</SPAN>
String timerKey = "ActionContextCleanUp_doFilter: "; UtilTimerStack.setActive(true); UtilTimerStack.push(timerKey); //调用要测试的方法。 UtilTimerStack.pop(timerKey);
8.核心源码
首先强调一下struts2的线程程安全,在Struts2中大量采用ThreadLocal线程局部变量的方法来保证线程的安全,
像Dispatcher等都是通过ThreadLocal来保存变量值,使得每个线程都有自己独立的实例变量,互不相干.
接下来就从Dispatcher开始看起,先看其构造函数:
- <SPAN style="FONT-SIZE: small">//创建Dispatcher,此类是一个Delegate,它是真正完成根据url解析转向,读取对应Action的地方
- public Dispatcher(ServletContext servletContext, Map<String, String> initParams) {
- this.servletContext = servletContext;
- //配置在web.xml中的param参数
- this.initParams = initParams;
- }</SPAN>
//创建Dispatcher,此类是一个Delegate,它是真正完成根据url解析转向,读取对应Action的地方 public Dispatcher(ServletContext servletContext, Map<String, String> initParams) { this.servletContext = servletContext; //配置在web.xml中的param参数 this.initParams = initParams; }
我们再看在FilterDispatcher创建Dispatcher的:
- <SPAN style="FONT-SIZE: small">protected Dispatcher createDispatcher(FilterConfig filterConfig) {
- Map<String, String> params = new HashMap<String, String>();
- for (Enumeration e = filterConfig.getInitParameterNames(); e.hasMoreElements();) {
- String name = (String) e.nextElement();
- String value = filterConfig.getInitParameter(name);
- params.put(name, value);
- }
- //都可以从FilterConfig中得到
- return new Dispatcher(filterConfig.getServletContext(), params);
- }</SPAN>
protected Dispatcher createDispatcher(FilterConfig filterConfig) { Map<String, String> params = new HashMap<String, String>(); for (Enumeration e = filterConfig.getInitParameterNames(); e.hasMoreElements();) { String name = (String) e.nextElement(); String value = filterConfig.getInitParameter(name); params.put(name, value); } //都可以从FilterConfig中得到 return new Dispatcher(filterConfig.getServletContext(), params); }
创建Dispatcher之后,来看init()方法
init()方法是用来Load用户配置文件,资源文件以及默认的配置文件.
主要分七步走,看下面注释
- <SPAN style="FONT-SIZE: small">public void init() {
- if (configurationManager == null) {
- //设置ConfigurationManager的defaultFrameworkBeanName.
- //这里DEFAULT_BEAN_NAME为struts,这是xwork框架的内容,Framework可以是xwork,struts,webwork等
- configurationManager = new ConfigurationManager(BeanSelectionProvider.DEFAULT_BEAN_NAME);
- }
- //读取properties信息,默认的default.properties,
- init_DefaultProperties(); // [1]
- //读取xml配置文件
- init_TraditionalXmlConfigurations(); // [2]
- //读取用户自定义的struts.properties
- init_LegacyStrutsProperties(); // [3]
- //自定义的configProviders
- init_CustomConfigurationProviders(); // [5]
- //载入FilterDispatcher传进来的initParams
- init_FilterInitParameters() ; // [6]
- //将配置文件中的bean与具体的类映射
- init_AliasStandardObjects() ; // [7]
- //构建一个用于依赖注射的Container对象
- //在这里面会循环调用上面七个ConfigurationProvider的register方法
- //其中的重点就是DefaultConfiguration的#reload()方法
- Container container = init_PreloadConfiguration();
- container.inject(this);
- init_CheckConfigurationReloading(container);
- init_CheckWebLogicWorkaround(container);
- if (!dispatcherListeners.isEmpty()) {
- for (DispatcherListener l : dispatcherListeners) {
- l.dispatcherInitialized(this);
- }
- }
- }</SPAN>
public void init() { if (configurationManager == null) { //设置ConfigurationManager的defaultFrameworkBeanName. //这里DEFAULT_BEAN_NAME为struts,这是xwork框架的内容,Framework可以是xwork,struts,webwork等 configurationManager = new ConfigurationManager(BeanSelectionProvider.DEFAULT_BEAN_NAME); } //读取properties信息,默认的default.properties, init_DefaultProperties(); // [1] //读取xml配置文件 init_TraditionalXmlConfigurations(); // [2] //读取用户自定义的struts.properties init_LegacyStrutsProperties(); // [3] //自定义的configProviders init_CustomConfigurationProviders(); // [5] //载入FilterDispatcher传进来的initParams init_FilterInitParameters() ; // [6] //将配置文件中的bean与具体的类映射 init_AliasStandardObjects() ; // [7] //构建一个用于依赖注射的Container对象 //在这里面会循环调用上面七个ConfigurationProvider的register方法 //其中的重点就是DefaultConfiguration的#reload()方法 Container container = init_PreloadConfiguration(); container.inject(this); init_CheckConfigurationReloading(container); init_CheckWebLogicWorkaround(container); if (!dispatcherListeners.isEmpty()) { for (DispatcherListener l : dispatcherListeners) { l.dispatcherInitialized(this); } } }
分七步载入各种配置属性,都是通过ConfigurationProvider接口进行的,这个接口提供init(),destroy(),register()等方法.
将各种ConfigurationProvider初始化之后将实例添加到ConfigurationManager的List里面.
最后通过循环调用List里的这些destroy(),register()等方法实现对配置文件的属性进行注册和销毁等功能.
相关推荐
Struts2 是一个基于MVC 模式的Web 应用程序框架,它的源码分析可以帮助我们更好地理解框架的内部机制和工作流程。下面是Struts2 源码分析的相关知识点: 1. Struts2 架构图 Struts2 的架构图主要包括 Filter chain...
Struts2是一个基于MVC(Model-View-Controller)设计模式的开源Java Web框架,它在Web应用开发中被广泛使用。这篇博文“Struts2源码解读”深入剖析了Struts2的核心机制,帮助开发者更好地理解和利用这个框架。源码...
Struts2是一个流行的Java Web应用程序框架,用于构建MVC(模型-视图-控制器)架构的应用。源码阅读对于理解其工作原理至关重要。本文将深入探讨Struts2的核心概念、类和请求处理流程。 首先,我们来看Struts2的架构...
Struts2是Java Web开发中一个非常重要的框架,它基于MVC(Model-View-Controller)设计模式,为开发者提供了一种结构化和可扩展的方式来构建动态网站应用程序。该框架自2005年发布以来,经过多次更新迭代,成为了...
Struts2是一个流行的Java web应用程序框架,它源自Struts1.x和WebWork的结合,具有稳定性和高性能。在深入理解Struts2的工作原理时,源码分析是必不可少的步骤。Struts2的核心设计理念和设计模式相比Struts1.x有了...
struts2源码详细解析51CTO下载-struts2源代码分析(个人觉得非常经典)
Struts 2是一个基于MVC(Model-View-Controller)设计模式的开源Java Web框架,由Apache软件基金会维护。它提供了强大的控制层,使得开发者能够更有效地构建动态、数据驱动的Web应用程序。Eclipse是一款广泛使用的...
本文将深入探讨Struts2的源码分析,特别是关于StrutsPrepareAndExecuteFilter的初始化过程,这是Struts2的核心组件之一,负责处理HTTP请求。 首先,我们来看`StrutsPrepareAndExecuteFilter`的初始化。这个过滤器...
本项目源码提供了一个基础的Struts2应用程序实例,对于初学者来说,这是一个很好的学习资源,可以深入理解Struts2的工作原理和架构。 Struts2的核心组件包括: 1. **Action类**:Action类是业务逻辑的载体,它是...
Struts2是一个非常著名的Java Web开发框架,由Apache软件基金会维护。版本2.1.8是Struts2的一个历史版本,它提供了许多功能和改进,旨在简化MVC(Model-View-Controller)架构的实现,提高开发效率。在这个版本中,...
Struts2是一个强大的MVC(Model-View-Controller)框架,它是Apache软件基金会下的一个开源项目,被广泛应用于Java EE应用程序开发中。Struts2框架是Struts1的升级版本,它结合了WebWork框架的优点,提供了更高效、...
STRUTS2源码解析STRUTS2源码解析STRUTS2源码解析STRUTS2源码解析STRUTS2源码解析STRUTS2源码解析STRUTS2源码解析STRUTS2源码解析STRUTS2源码解析STRUTS2源码解析STRUTS2源码解析STRUTS2源码解析STRUTS2源码解析...
Struts2是一个基于MVC(Model-View-Controller)设计模式的开源JavaEE框架,它极大地简化了企业级Web应用的开发。这个压缩包“struts-2.3.1”很可能包含了Struts2框架的源代码,版本为2.3.1。在这个版本中,我们可以...
Struts2是一个流行的Java Web框架,它为开发者提供了一种结构化的MVC(Model-View-Controller)架构来构建应用程序。在"struts2源码解析.pdf"文档中,主要探讨了以下几个关键组件及其功能: 1. **ActionContext**:...
Struts 2是Java Web开发中的一个开源框架,它基于MVC(Model-View-Controller)设计模式,用于构建高效、可扩展的企业级应用程序。在深入理解Struts 2的源码之前,我们需要先了解其核心概念和组件。 1. **Action类...
Struts2是一个基于MVC(Model-View-Controller)设计模式的开源Java Web框架,它在Web应用开发中被广泛使用。源码分析是深入理解一个框架工作原理的关键步骤,对于提升开发技能和解决问题有着不可估量的价值。下面将...
Struts2是一个强大的Java web开发框架,用于构建可维护、可扩展且结构良好的应用程序。它提供了MVC(Model-View-Controller)设计模式的实现,极大地简化了开发过程。在这个"Struts2演示源码"中,我们可以深入理解...
Struts2框架是Java Web开发中的一个流行框架,它基于MVC(Model-View-Controller)设计模式,为开发者提供了一种...通过研究源码,不仅可以提升对Struts2的理解,还能帮助你在实际项目中更有效地应用和优化这一框架。
Struts2是一个基于MVC(Model-View-Controller)设计模式的开源Java Web框架,它在Web应用开发中被广泛使用。源码分析是深入理解框架工作原理、优化代码以及解决实际问题的重要途径。这里我们将重点探讨Struts2的...