Struts2 技术内幕Struts2执行流程001Word格式文档下载.docx
- 文档编号:21164639
- 上传时间:2023-01-28
- 格式:DOCX
- 页数:48
- 大小:1,011.56KB
Struts2 技术内幕Struts2执行流程001Word格式文档下载.docx
《Struts2 技术内幕Struts2执行流程001Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《Struts2 技术内幕Struts2执行流程001Word格式文档下载.docx(48页珍藏版)》请在冰豆网上搜索。
//配置哪些形式的URL模式被排除在Struts2的处理之外
protectedList<
Pattern>
excludedPatterns=null;
//Filter的初始化过程
publicvoidinit(FilterConfigfilterConfig)throwsServletException{
//初始化操作类
InitOperationsinit=newInitOperations();
try{
FilterHostConfigconfig=newFilterHostConfig(filterConfig);
init.initLogging(config);
//初始化核心分发器Dispatcher
Dispatcherdispatcher=init.initDispatcher(config);
//初始化静态资源加载器
init.initStaticContentLoader(config,dispatcher);
//初始化进行Http预处理的操作类
prepare=newPrepareOperations(filterConfig.getServletContext(),dispatcher);
//初始化进行Http请求处理的逻辑执行的操作类
execute=newExecuteOperations(filterConfig.getServletContext(),dispatcher);
this.excludedPatterns=init.buildExcludedPatternsList(dispatcher);
//自定义的初始化过程,留作用户扩展
postInit(dispatcher,filterConfig);
}finally{
//初始化中的清理工作
init.cleanup();
}
*Callbackforpostinitialization
*初始化中的扩展工作
protectedvoidpostInit(Dispatcherdispatcher,FilterConfigfilterConfig){
//处理Http请求的入口方法
publicvoiddoFilter(ServletRequestreq,ServletResponseres,FilterChainchain)throwsIOException,ServletException{
HttpServletRequestrequest=(HttpServletRequest)req;
HttpServletResponseresponse=(HttpServletResponse)res;
//====步骤1开始====
//设置Encoding和Locale
prepare.setEncodingAndLocale(request,response);
//====步骤1结束====
//====步骤2开始====
//创建Action执行所对应的ActionContext
prepare.createActionContext(request,response);
//====步骤2结束====
//====步骤3开始====
//把核心分发器Dispatcher分配至当前线程
prepare.assignDispatcherToThread();
//====步骤3结束====
//处理被过滤的URL
if(excludedPatterns!
=null&
&
prepare.isUrlExcluded(request,excludedPatterns)){
chain.doFilter(request,response);
}else{//真正需要进行URL处理的逻辑起始
//====步骤4开始====
//首先对request进行一定的封装
request=prepare.wrapRequest(request);
//====步骤4结束====
//====步骤5开始====
//根据request请求查找ActionMapping
ActionMappingmapping=prepare.findActionMapping(request,response,true);
//====步骤5结束====
//没有找到对应的ActionMapping
if(mapping==null){
//判断是否将URL处理为静态资源
booleanhandled=execute.executeStaticResourceRequest(request,response);
if(!
handled){
chain.doFilter(request,response);
}
}else{
//执行URL请求的处理
execute.executeAction(request,response,mapping);
}
}
//清理Request
prepare.cleanupRequest(request);
publicvoiddestroy(){
//清理核心分发器Dispatcher
prepare.cleanupDispatcher();
}
从源码上来看,init方法的主要内容是针对三个元素展开的,而这三个元素也成为之后Http请求处理这一条逻辑主线的执行依据。
这三个元素分别是:
❑Dispatcher——核心分发器
❑PrepareOperations——Http预处理类
❑ExecuteOperations——Http处理执行类
其实,PrepareOperations和ExecuteOperations只是Struts2在第二条运行主线中的执行句柄,其真正的意义仅仅在于两者对Http请求的处理职责不同。
当然,职责的不同也直接成为Struts2对Http请求的处理流程进行逻辑划分的依据。
有关这一点,我们在后续章节还会讲到。
而入口程序StrutsPrepareAndExecuteFilter的init方法的核心,则是通过init.initDispatcher方法的调用返回核心分发器Dispatcher的实例。
该方法的相关源码如代码清单9-2所示。
代码清单9-2 InitOperations.java
packageorg.apache.struts2.dispatcher.ng;
*Createsandinitializesthedispatcher
*创建并初始化dispatcher对象
publicDispatcherinitDispatcher(HostConfigfilterConfig){
//创建核心分发器Dispatcher的实例
Dispatcherdispatcher=createDispatcher(filterConfig);
//调用Dispatcher实例的init方法完成核心分发器的初始化
dispatcher.init();
returndispatcher;
*Createa{@linkDispatcher}
*创建Dispatcher实例
privateDispatchercreateDispatcher(HostConfigfilterConfig){
Map<
String,String>
params=newHashMap<
();
for(Iteratore=filterConfig.getInitParameterNames();
e.hasNext();
){
Stringname=(String)e.next();
Stringvalue=filterConfig.getInitParameter(name);
params.put(name,value);
returnnewDispatcher(filterConfig.getServletContext(),params);
在这里,我们还是没有从代码中看出什么实质的内容。
createDispatcher方法将filterConfig中的初始化参数通过构造函数传入Dispatcher来创建一个新的Dispatcher实例并返回。
其中,filterConfig中所包含的参数其实来自于web.xml中的初始化参数配置。
要是读者以为这个过程只是像看上去那么简单,就大错特错了。
因为在这段代码中,虽然Dispatcher的实例创建过程并不复杂,但其中init方法的内涵却是极其丰富的。
这个init方法是核心分发器Dispatcher进行自身初始化的入口方法,同时也是整个Struts2初始化主线的入口方法,其内容将包含整个Struts2的初始化主线的全部过程,我们将在之后单独进行源码解析。
9.1.2 初始化主线的核心驱动力
任何程序的运行都有其内在的核心驱动力。
所谓核心驱动力,其实是指某一段程序运行的最终目的是什么。
因而,要弄清楚一段程序或者一条程序运行的主线,我们必须从逻辑和形式这两个不同的方面对核心驱动力进行解读:
❑核心驱动力的逻辑——对于程序运行目的的描述
❑核心驱动力的形式——推动程序运行的编程元素
对于Struts2的初始化主线而言,我们已经反复强调过核心驱动力的逻辑:
对Struts2/XWork元素的规划和管理。
那么,作为核心驱动力的具体表现形式,到底是什么样的编程元素推动着初始化主线的运作呢?
我们依然采用算法和数据结构这两个构成程序的抽象元素来进行描述:
❑数据结构——框架的核心配置元素
❑算法——围绕着核心配置元素的初始化过程
在第3章中,我们曾经提到过与框架的核心配置元素相关的一个重要观点,我们在这里不妨重新来审视一下:
【结论】 框架的核心配置是一种贯穿始终的核心驱动力,它不仅能够以一定的形式表现出框架的构成元素互相之间的逻辑关系,同时能够将它们的执行逻辑串联起来。
之前对于这个结论的理解,停留在了对框架元素的构成层面。
结合初始化主线的算法逻辑,我们就会发现整个初始化主线所围绕的核心,不正是对框架的核心配置进行管理吗?
事实上,在初步领略了Struts2所支持的所有配置表现形式(包括XML文件的形式,也有Properties文件的形式;
既有系统级别的配置,也有应用级别的配置)之后,我们就不难从这些纷繁复杂的配置形式中总结出一条逻辑主线:
【结论】 Struts2初始化主线的核心驱动力,正是对各种配置形式所进行的一次统一的对象化处理。
这个结论不仅是Struts2初始化过程的核心结论,也是贯穿所有Struts2配置元素运作方式的一条逻辑主线。
有了这一结论,我们才可以把Struts2的配置元素的运行特性真正讲清楚。
那么,什么是“对象化处理”呢,对配置元素进行“对象化处理”的最终目的又是什么呢?
因为配置元素本身无论从形式上还是内容的定义上,都有太多的不确定性。
这些不确定性直接导致了框架在处理这些配置元素时,缺乏一个统一的处理模式。
但是,如果换一个角度来思考这个问题,我们会发现无论哪种形式的配置文件,它们最终反映到框架运行之中,都表现为一个个Java对象或者运行参数。
因此,“对象化处理”实际上说的是Struts2在初始化的时候,将各种各样的配置元素,无论是XML形式还是Properties文件形式(甚至可能是其他自定义的配置形式)转化为Struts2所定义的Java对象或者Struts2运行时的参数的处理过程。
由此,我们从逻辑上总结了Struts2初始化主线的核心驱动力。
站在数据结构的角度,Struts2初始化主线的操作对象正是这些配置元素;
而站在算法的角度,我们还需要探究这些操作对象的逻辑调度元素。
在代码清单9-1中,我们已经看到了这一逻辑调度元素:
核心分发器(Dispatcher)。
对于核心分发器我们并不陌生,我们在本书的第二部分讲XWork的时候就曾经介绍过它。
当时,我们还为核心分发器与XWork框架之间的关系单独做了一番描述:
它们之间形成一个明显的调用关系。
对于初始化主线而言,我们可以非常清楚地看到整个初始化的最终过程,被分派到了Dispatcher的init方法中去执行。
所以Dispatcher对象的来龙去脉,也就成为了整个初始化主线的重中之重。
就初始化主线本身而言,它是一个非常复杂的过程。
因而它离不开许多辅助对象的帮助。
Dispatcher对象作为一个核心元素,也需要这些辅助对象的帮助才能够顺利承担起核心分发器的重要职责。
接下来,我们就来看看构成初始化主线的主要元素。
9.1.3 初始化主线的构成元素
本章的标题是“包罗万象”,这一标题实际上包含了两层意思:
其一,在Struts2的初始化主线中需要处理的内置元素非常多,谓之“万象”;
其二,Struts2对于所有这些元素对象进行的管理,谓之“包罗”。
有关“万象”的话题,其实早在第3章中就已经给读者进行了介绍,并为这些对象找到了一个合适的切入点:
配置元素。
配置元素不仅表现形式纷繁复杂,其内在含义也各有不同。
然而,有关“包罗”的话题,我们却未曾提及。
这也可以理解,因为对于配置元素的处理过程正是Struts2初始化主线所要做的,也是本章的重点内容。
Struts2在初始化主线中,为了对形式上纷繁复杂、内容含义又各异的配置元素进行处理,不得不创建一些额外的辅助对象,这些对象实际上是对上述配置元素进行操作的流程元素。
构成这些流程元素的对象,主要有三个不同的类别:
❑配置元素的加载器
配置元素的加载器主要用于将纷繁复杂的配置表现形式转化为框架元素,相当于在不同的配置形式和框架之间建立起沟通的桥梁。
❑配置元素的构造器
配置元素的构造器主要用于对框架元素进行初始化操作。
在这里,Struts2采用的是设计模式中的构造模式。
❑配置元素的管理类
配置元素的管理类主要是指在初始化主线运行的过程中,对配置元素的数据的存储和配置元素的初始化行为进行控制的配置管理元素。
这三大不同类别的元素都是构成Struts2初始化主线中的主要流程元素,结合上一节中提到的核心驱动力元素:
核心分发器,我们可以发现整个Struts2在初始化主线的设计上考虑得也十分周到。
在接下来的章节中,我们将分别对这些元素进行分析和讲解,最后将它们综合在一起,探寻它们的执行轨迹。
9.2 核心分发器——Dispatcher
9.2.1 核心分发器的核心驱动作用
Dispatcher之所以被称为Struts2的核心分发器,主要是基于它在整个Struts2框架中的特殊地位。
我们经常会使用“起——承——转——合”这4个不同的阶段来描述一个事件的整个过程,对于Struts2而言,Dispatcher实际上就是囊括这4个阶段的核心分发器。
9.2.1.1 起——负责系统初始化
Dispatcher在初始化时负责整个Struts2的初始化工作。
在Dispatcher中,init方法会在Dispatcher创建之初被调用,从而触发整个Struts2的初始化过程。
所有的初始化方法在Dispatcher中都以init加上下划线作为起始进行命名,如图9-1所示。
图 9-1 Dispatcher的初始化方法列表
从图中,我们可以看到init方法是一个public方法,是整个初始化过程中的操作窗口。
而其余的所有以init加上下划线命名的方法,都将在init方法中以一定的顺序被依次调用。
这些方法涵盖了在Dispatcher进行初始化过程中逻辑的方方面面。
我们将在之后的源码分析中为读者详细解读。
9.2.1.2 承——接收并预处理Http请求
Dispatcher需要负责对Http请求进行预处理。
这些预处理的过程主要包括:
设置Encoding和Locale、对HttpServletRequest进行封装以及准备MVC运行的数据环境等。
这些预处理过程,由PrepareOperations在进行Http请求预处理的这个阶段调用执行。
而我们知道PrepareOperations对象本身只是一个操作代理接口,真正完成逻辑功能的是Dispatcher本身。
PrepareOperations在内部实现中所做的,只是对每个操作做了一个简单的转发处理。
这些方法如图9-2所示。
图 9-2 Dispatcher的Http请求预处理方法
注意在这其中的两个createContextMap方法。
在这两个方法中,Dispatcher把Web容器相关的数据对象封装成了普通的Java对象(实际上被封装成了Map对象)。
这对于整个框架的意义不亚于任何其他的精妙设计。
因为这两个方法的核心要义在于将Web请求数据进行“去容器化”处理,使得后续依赖于Web请求的任何操作不再受限于任何的Web容器对象,从而真正做到了解耦合。
读者可以结合在之前XWork章节中,我们对ActionContext初始化的相关描述,createContextMap方法实际上成为了ActionContext这个数据环境内部构造上下文环境的数据基础。
9.2.1.3 转——将Struts2转入XWork
在第3章中,我们提到Struts2在处理Http请求时还可以分为2个阶段,而划分这2个阶段的临界点实际上就在于Dispatcher对象。
在第一个阶段中,所有的Http请求通过Dispatcher对象的Http请求的预处理,请求中与Web容器相关的对象全部被封装成与Web容器无关的对象,并构造出一个数据环境。
于是,在第二个阶段中Dispatcher就能够将这一数据环境转发到XWork框架中执行,从而保证解耦合在这一刻彻底完成。
Dispatcher中进行请求转发的方法是serviceAction,如图9-3所示。
图 9-3 Dispatcher的请求转发方法
我们可以看到,serviceAction方法与Servlet规范中的service方法有着异曲同工之妙。
只是在这里,serviceAction方法并不是Http请求处理的“终点”,反而是Struts2/XWork中进行Http请求处理的“起点”和“中转站”。
serviceAction方法是整个Dispatcher对象的逻辑调度核心方法,也是整个Struts2在Http请求处理阶段的核心逻辑。
我们将在下一章中对这个方法进行源码解读。
9.2.1.4 合——垃圾清理
Dispatcher不仅负责逻辑执行,还要负责在执行完毕之后进行对象清理。
这一工作是由cleanup方法完成的,如图9-4所示。
图 9-4 Dispatcher的垃圾清理方法
在Dispatcher的cleanup方法中,将完成对Http请求的处理过程中产生的请求周期的对象的清理工作。
在这里不再展开对其源码的分析,不过我们可以将其源码中所涉及的清理对象进行逻辑分类:
❑对于在整个请求周期中定义了完整的生命周期的框架元素的清理
例如,我们之前讲过的XWork中Interceptor对象,其接口定义中就蕴含了destroy方法。
这个方法就会在cleanup的流程中被调用执行。
❑对于线程安全的ThreadLocal对象的清理
我们知道,XWork中的ActionContext作为一个数据环境使用了ThreadLocal模式在整个当前线程共享数据,那么在整个请求结束时,与当前线程绑定的ActionContext的副本也在cleanup方法中被清理。
9.2.2 核心分发器的数据结构
Dispatcher中的内容如此丰富,以至于它成为我们进行Struts2研究的最重要线索。
之前我们已经看到了Dispatcher在不同阶段所承担的不同职责。
接下来,我们从数据结构的角度来看看Dispatcher有什么独特之处。
翻开Dispatcher的源码,我们可以看到Dispatcher内部的属性构成,源代码如代码清单9-3所示。
代码清单9-3 Dispatcher.java
packageorg.apache.struts2.dispatcher;
publicclassDispatcher{
//这里省略了许多其他代码
/**
*Provideathreadlocalinstance.
*提供了一个静态的ThreadLocal变量
privatestaticThreadLocal<
Dispatcher>
instance=newThreadLocal<
*Providethedispatcherinstanceforthecurrentthread.
*提供一个接口方法,用于获取当前线程安全的Dispatcher实例
*
*@returnThedispatcherinstance
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Struts2 技术内幕Struts2执行流程001 技术 内幕 执行 流程 001