核心分发器

简介:

9.2核心分发器 —— Dispatcher 

9.2.1 核心分发器(Dispatcher)的核心驱动作用 

Dispatcher之所以被称之为Struts2的核心分发器,主要是基于它在整个Struts2框架中的特殊地位。我们经常会使用“起-承-转-合”这4个不同的阶段来描述一个事件的整个过程,对于Struts2而言,Dispatcher实际上就是囊括这4个阶段的核心分发器。 

9.2.1.1起 —— 负责系统初始化 

Dispatcher在初始化时负责整个Struts2的初始化工作。在Dispatcher中,init()方法会在Dispatcher创建之初被调用,从而触发整个Struts2的初始化过程。所有的初始化方法在Dispatcher中都以init加上下划线作为起始进行命名,如图9-1所示: 

 

从图中,我们可以看到init方法是一个public方法,是整个初始化过程中的操作窗口。而其余的所有以init加上下划线命名的方法,都将在init方法中以一定的顺序被依次调用。这些方法涵盖了在Dispatcher进行初始化过程中逻辑的方方面面。我们将在之后的源码分析中为读者详细解读。 

9.2.1.2承 —— 接收并预处理Http请求 

Dispatcher需要负责对Http请求进行预处理。这些预处理的过程主要包括:设置Encoding和Locale、对HttpServletRequest进行封装以及准备MVC运行的数据环境等。 

这些预处理过程,由PrepareOperations在进行Http请求预处理的这个阶段调用执行。而我们知道PrepareOperations对象本身只是一个操作代理接口,真正完成逻辑功能的是Dispatcher本身。PrepareOperations在内部实现中所做的,只是对每个操作做了一个简单的转发处理。这些方法如图9-2所示: 



注意在这其中的两个createContextMap方法,在这两个方法中,Dispatcher把Web容器相关的数据对象,封装成了普通的Java对象(实际上被封装成了Map对象)。这对于整个框架的意义不亚于任何其他任何的精妙设计。因为这两个方法的核心要义在于将Web请求数据进行“去容器化”处理,使得后续依赖于Web请求的任何操作,不再受限于任何的Web容器对象,从而真正做到了解耦合。读者可以结合在之前XWork章节中,我们对ActionContext初始化的相关描述,createContextMap方法实际上成为了ActionContext这个数据环境内部构造上下文环境的数据基础。 

9.2.1.3转 —— 将Struts2转入XWork 

在第三章中,我们提到Struts2在处理Http请求时还可以被分为2个阶段,而划分这2个阶段的临界点实际上就在于Dispatcher对象。 

在第一个阶段中,所有的Http请求通过Dispatcher对象的Http请求的预处理,请求中与Web容器相关的对象全部被封装成与Web容器无关的对象,并构造出一个数据环境。于是,在第二个阶段中Dispatcher就能够将这一数据环境转发到XWork框架中执行,从而保证解耦在这一刻彻底完成。Dispatcher中进行请求转发的方法是serviceAction,如图9-3所示: 

 

我们可以看到,serviceAction方法与Servlet规范中的service方法有着异曲同工之妙。只是在这里,serviceAction方法并不是Http请求处理的“终点”,反而是Struts2 / XWork中进行Http请求处理的“起点”和“中转站”。 

serviceAction方法是整个Dispatcher对象的逻辑调度核心方法,也是整个Struts2在Http请求处理阶段的核心逻辑。我们将在下一章中对这个方法进行源码解读。 

9.2.1.4合 —— 垃圾清理 

Dispatcher不仅负责逻辑执行,还要负责在执行完毕之后进行对象清理。这一工作是由cleanup方法完成的,如图9-4所示: 

 

在Dispatcher的cleanup方法中,将完成对Http请求的处理过程中产生的请求周期的对象的清理工作。我们在这里不再展开其源码的分析,不过我们可以将其源码中所涉及到的清理对象进行逻辑分类: 

对于在整个请求周期中定义了完整的生命周期的框架元素的清理 

例如,我们之前讲过的XWork中Interceptor对象,其接口定义中就蕴含了destroy方法。这个方法,就会在cleanup的流程中被调用执行。 

对于线程安全的ThreadLocal对象的清理 

我们知道,XWork中的ActionContext作为一个数据环境使用了ThreadLocal模式在整个当前线程共享数据,那么在整个请求结束时,与当前线程绑定的ActionContext的副本也在cleanup方法中被清理。 

9.2.2 核心分发器(Dispatcher)的数据结构 

Dispatcher中的内容如此丰富,以至于它成为了我们进行Struts2研究的最重要线索。之前我们已经看到了Dispatcher在不同阶段所承担的不同职责。接下来,我们从数据结构的角度来看看Dispatcher有什么独特之处。翻开Dispatcher的源码,我们可以看到Dispatcher内部的属性构成,源代码如代码清单9-3所示: 

Java代码   收藏代码
  1. public class Dispatcher {  
  2.       
  3.     // 这里省略了许多其它代码  
  4.   
  5.     /** 
  6.      * 提供了一个静态的ThreadLocal变量 
  7.      */  
  8. private static ThreadLocal<Dispatcher> instance = new ThreadLocal<Dispatcher>();  
  9.   
  10.     /** 
  11.      * 提供一个接口方法,用于获取当前线程安全的dispatcher实例 
  12.      * 
  13.      * @return  
  14.      */  
  15.     public static Dispatcher getInstance() {  
  16.         return instance.get();  
  17.     }  
  18.   
  19.     /** 
  20.      * 将dispatcher实例绑定到当前线程 
  21.      * 
  22.      * @param instance 
  23.      */  
  24.     public static void setInstance(Dispatcher instance) {  
  25.         Dispatcher.instance.set(instance);  
  26.     }  
  27. }  



这个非常惹眼的内部变量instance,它不仅是一个静态的实例变量,同时它也被定义成为ThreadLocal类型,而ThreadLocal所承载的实际类型是Dispatcher本身!这正是一个典型的ThreadLocal模式的应用范例! 

从这个数据结构的定义来看,我们可以确认,Struts2对Dispatcher应用了ThreadLocal模式。其中,Dispatcher本身就是实现ThreadLocal模式的核心要素,因为我们实际上在Dispatcher中看到了实现ThreadLocal模式的两大步骤。在之后的源码分析中,我们还将看到Dispatcher在处理Http请求时与ThreadLocal变量的交互过程。 

使用ThreadLocal模式的初衷是为了解决多线程环境下对象访问的线程安全问题。Dispatcher作为核心分发器,成为了入口程序StrutsPrepareAndExecuteFilter中的实例变量PrepareOperations和ExecuteOperations的实际操作句柄(Dispatcher是它们的重要实例变量),从而被所有的线程共享访问。因此,Dispatcher被打造成ThreadLocal模式是一个理所当然的选择。 

然而,这一理所当然的选择,却使得Struts2能够摆脱传统的表示层框架对于Web容器的高度依赖。由此可见,ThreadLocal模式是贯穿整个Struts2的核心技术之一,成为了Struts2将Web容器与Java开发解耦合的内在基础。不仅如此,我们还将在之后的章节中看到ThreadLocal模式在Struts2数据流转的过程中所起到的决定性作用。 

最后,有两个针对Dispatcher重要结论需要强调一下: 

downpour 写道
结论 Dispatcher作为一个线程安全的对象,涵盖了整个Struts2的生命周期。无论是Struts2的初始化,还是处理Http请求,实际都在Dispatcher中完成。



这个结论所针对的角度是Dispatcher的内容和职责,将它牢记于心,有助于日后我们对Struts2相关问题的调试和分析。实际上,对于Struts2的运行机理的一切研究,都离不开Dispatcher这个核心分发器。Dispatcher中所包含的所有方法,从一个侧面反应了Struts2框架的几个主要功能,而Dispatcher则处于一个“居中调度”的重要位置。 

downpour 写道
结论 Dispatcher是Struts2与XWork的分界点,也是将MVC实现与Web容器隔离的分界点。



这个结论则从另外一个角度描述了Dispatcher在整个Struts2框架中的重要地位。它也成为了Struts2实现“解耦合”的核心所在。我们将在Struts2的第二条主线的分析中看到这个分界点以及它在框架中的逻辑意义。 



原文链接:[http://wely.iteye.com/blog/2295281]

相关文章
|
25天前
|
消息中间件 Java RocketMQ
【深度挖掘 RocketMQ底层源码】「底层源码挖掘系列」抽丝剥茧贯穿RocketMQ的消费者端的运行核心的流程(Pull模式-下)
【深度挖掘 RocketMQ底层源码】「底层源码挖掘系列」抽丝剥茧贯穿RocketMQ的消费者端的运行核心的流程(Pull模式-下)
12 1
|
25天前
|
消息中间件 Java 调度
【深度挖掘RocketMQ底层源码】「底层源码挖掘系列」透彻剖析贯穿RocketMQ的消费者端的运行调度的流程(Pull模式)
【深度挖掘RocketMQ底层源码】「底层源码挖掘系列」透彻剖析贯穿RocketMQ的消费者端的运行调度的流程(Pull模式)
12 1
|
人工智能 负载均衡 监控
支付宝定时任务怎么做?三层分发任务处理框架介绍
本文将从单机定时调度开始,循序渐进地带领大家了解五福定制三层分发任务处理框架。
24533 3
支付宝定时任务怎么做?三层分发任务处理框架介绍
|
存储 缓存 算法
内容分发网络 | 学习笔记
快速学习内容分发网络,介绍了内容分发网络系统机制, 以及在实际应用过程中如何使用。
144 0
内容分发网络 | 学习笔记
|
负载均衡 API 调度
语聊源码,任务分发系统需要具备的功能
语聊源码,任务分发系统需要具备的功能
|
前端开发 UED 开发者
手机直播源码中消息系统的构建,四大管理模块的作用
手机直播源码中消息系统的构建,四大管理模块的作用
|
存储 资源调度 Java
分布式调度组件整合设计解析
分布式调度组件从落地到如今已有一年多的时间,作为组件开发者在其中过程中也在不断思考该组件的实现提升点以及后续的功能拓展接入。 作为一个整合类型的组件设计,从使用者的角度来看,应该更多地掩盖整合前各种接入实现,专心关注在当前组件的使用过程。因此,整合过程中的第一要素,就是要拉平多个整合组件的差异,包括数据模型、功能实现、以及外部透出的呈现,保证不同底层实现的无缝切换。第二就是简化对接工作量,把常用配置项默认固化,减轻使用方的对接成本,专心关注到业务中去。
|
小程序 数据可视化 安全
HaaS UI小程序解决方案应用分发之一:业务简介
智能物联网进展至今,要想形成竞争力,必须要有一套闭环的端云一体解决方案,Iot硬件端有Haas公版,可视化上有IOT小程序解决方案,工具上提供了Haas Studio开发套件,急需云端有一套应用分发系统来实现端云一体的闭环。
HaaS UI小程序解决方案应用分发之一:业务简介
|
存储 前端开发 安全
|
对象存储
[内容协作平台] 快速搭建一个数据分发系统
本篇讲介绍如何基于CCP搭建一个数据分发系统。 1. 创建域实例 域(domain):是一个独立的资源空间,比如一个分发系统或一个网盘系统。 (1) 登录CCP官网控制台,创建一个域实例。 点击"创建域"按钮, 数据存储方式,选择 OSSPath: 2. 创建OSS Bucket 打开OSS控制台: https://oss.console.aliyun.com (1) 新建bucket OSS Bucket 区域可以选择任意区域,不一定要和CCP的区域一致。
3116 0

热门文章

最新文章