Struts2 源码分析——调结者(Dispatcher)之准备工作
| 章节简言 |
上一章笔者讲到关于struts2过滤器(Filter)的知识。让我们了解到StrutsPrepareFilter和StrutsExecuteFilter的作用。特别是StrutsPrepareFilter做了重要的讲解。从其中我们了解到Dispatcher类的重要性。而本章就是专对Dispatcher类的工作进行讲解。从前面章节的机制图片中我们橙黄色区里面看到FilterDispatcher。在笔者理解这里的FilterDispatcher相当于Dispatcher类的工作。那么到底Dispatcher类做了哪一些的工作呢?本章就是笔者就会详细的进行讲解。那么在讲解之前笔者还是有想把一些必要的知识说一下。从上一章中我们可以明白StrutsPrepareFilter类的主要工作有俩点:一是为struts2执行做一些相关的准备。如加载相关的配置信息。二是为struts2的request请求处理相关的信息。如设置编码格式和找到对应的action映射类。而这二点都离不开Dispatcher类的作用。甚至可以讲大部分都要靠Dispatcher类来完成。笔者很想把Dispatcher类的源码全部都POST上来。可是想到这样子读起来有一点吃力。所以笔者打算将来部分部分的POST上来进行讲解。
| 调结者的准备工作 |
在执行struts2之前必然要加载一些相关信息。如配置文件struts.xml之类。没有错。StrutsPrepareFilter就是通过Dispatcher类来完成这一系列的工作的(下面代码的红色部分)。让我们看一下Dispatcher类的代码就是能够明白。如下
StrutsPrepareFilte类:
public void init(FilterConfig filterConfig) throws ServletException {
InitOperations init = new InitOperations();//用于初始化相关的功能操作。你可以理解为工具类一样子。
Dispatcher dispatcher = null;//这个类相当的重要。他的作用连接着StrutsExecuteFilter。这里可以命名为调结者。
try {
FilterHostConfig config = new FilterHostConfig(filterConfig);//这里可以理解为把filterConfig在进行封装FilterHostConfig更为主便操作和理解。
init.initLogging(config);//获取名为loggerFactory的参数,并实例化这个类。一般为去用户自定义日志。
dispatcher = init.initDispatcher(config);//初化调结者。这里是重要。
prepare = new PrepareOperations(dispatcher);
this.excludedPatterns = init.buildExcludedPatternsList(dispatcher);//加载排除在内的action的正则表达式
postInit(dispatcher, filterConfig);
} finally {
if (dispatcher != null) {
dispatcher.cleanUpAfterInit();
}
init.cleanup();
}
}
Dispatcher类:
public void init() {
if (configurationManager == null) {
configurationManager = createConfigurationManager(DefaultBeanSelectionProvider.DEFAULT_BEAN_NAME);// 初始化配置管理类
}
try {
init_FileManager();// 初始化FileManager类的供应者
init_DefaultProperties(); // [1]初始化default.properties信息的供应者
init_TraditionalXmlConfigurations(); // [2]初始化struts-default.xml,struts-plugin.xml,struts.xml信息的供应者
init_LegacyStrutsProperties(); // [3]初始化struts.properties信息的供应者
// 可能是以前版本留下的文件。在这里笔者一直没有找到
init_CustomConfigurationProviders(); // [5]初始化用户struts.xml信息的供应者
init_FilterInitParameters(); // [6]初始化用户传入的过滤器参数信息的供应者
init_AliasStandardObjects(); // [7]初始化struts-default.xml,struts-plugin.xml,struts.xml进行别名信息的供应者
Container container = init_PreloadConfiguration();// 初始化相关的配置信息,并加载以上供应者。
container.inject(this);// 注入当前类依赖项的信息。
init_CheckWebLogicWorkaround(container);
if (!dispatcherListeners.isEmpty()) {
for (DispatcherListener l : dispatcherListeners) {
l.dispatcherInitialized(this);
}
}
errorHandler.init(servletContext);
} catch (Exception ex) {
LOG.error("Dispatcher initialization failed", ex);
throw new StrutsException(ex);
}
}
以上的源码就是Dispatcher类加载相关配置信息工作的代码。从上面的注解中我们可以看“供应者”这三个字样。为什么这边笔者要叫他们为供应者。主要是struts2这边用到了一个概念就是IOC思想。即是控制反转(Inversion of Control)。简单点理解IOC就是有一个容器,里面有很多要用到的实例或是类的信息。当开发员要用到某个类的实例的时候,不在是NEW了。而是通过当前容器来获得实例。即是有一点类似于工厂模式。如果还是不能理解的话,请读者自行去找一些相关IOC思想的文章。笔者这里不会细说IOC思想。 Container类的实例就是笔者所讲的容器。而前面的供应者是为Container容器提供对应的类的信息或实例。确切的讲Container容器创建的时候,就会去找所有供应者并让供应者提供数据。值得一提的是这里面还有涩及到一个重要的中间人配置管理类(ConfigurationManager)。让我们看一下下面的代码,就是知道是什么一回事了。如下
/**
* 初始化文件管理器供应者
*/
private void init_FileManager() throws ClassNotFoundException {
if (initParams.containsKey(StrutsConstants.STRUTS_FILE_MANAGER)) {
final String fileManagerClassName = initParams.get(StrutsConstants.STRUTS_FILE_MANAGER);
final Class<FileManager> fileManagerClass = (Class<FileManager>) Class.forName(fileManagerClassName);
LOG.info("Custom FileManager specified: {}", fileManagerClassName);
configurationManager
.addContainerProvider(new FileManagerProvider(fileManagerClass, fileManagerClass.getSimpleName()));
} else {
// add any other Struts 2 provided implementations of FileManager
configurationManager.addContainerProvider(new FileManagerProvider(JBossFileManager.class, "jboss"));
}
if (initParams.containsKey(StrutsConstants.STRUTS_FILE_MANAGER_FACTORY)) {
final String fileManagerFactoryClassName = initParams.get(StrutsConstants.STRUTS_FILE_MANAGER_FACTORY);
final Class<FileManagerFactory> fileManagerFactoryClass = (Class<FileManagerFactory>) Class
.forName(fileManagerFactoryClassName);
LOG.info("Custom FileManagerFactory specified: {}", fileManagerFactoryClassName);
configurationManager.addContainerProvider(new FileManagerFactoryProvider(fileManagerFactoryClass));
}
} /**
* 初始化加载default.properties文件信息的供应者
*/
private void init_DefaultProperties() {
configurationManager.addContainerProvider(new DefaultPropertiesProvider());
} private void init_LegacyStrutsProperties() {
configurationManager.addContainerProvider(new PropertiesConfigurationProvider());
} /**
* 初始化struts-default.xml,struts-plugin.xml,struts.xml信息的供应者
*/
private void init_TraditionalXmlConfigurations() {
String configPaths = initParams.get("config");
if (configPaths == null) {
configPaths = DEFAULT_CONFIGURATION_PATHS;
}
String[] files = configPaths.split("\\s*[,]\\s*");
for (String file : files) {
if (file.endsWith(".xml")) {
if ("xwork.xml".equals(file)) {
configurationManager.addContainerProvider(createXmlConfigurationProvider(file, false));
} else {
configurationManager
.addContainerProvider(createStrutsXmlConfigurationProvider(file, false, servletContext));
}
} else {
throw new IllegalArgumentException("Invalid configuration file name");
}
}
}
看到上面的红色代码了吗?没有错。从这一点我们就是看出来。所以初始化的操作都是先创建对应的供应者。并把供应者实列增加到ConfigurationManager实例中去。正如上面所讲的供应者是为Container容器提供数据的。那么到底供应者又长什么样子呢?这就不得不让我们在看另一段代码了。如下
package com.opensymphony.xwork2.config; import com.opensymphony.xwork2.inject.ContainerBuilder;
import com.opensymphony.xwork2.util.location.LocatableProperties; /**
* 用于给Container容器提供对应的对象,常量和属性的供应者类
*
* @since 2.1
*/
public interface ContainerProvider { /**
* 消毁当前的供应者
*/
public void destroy(); /**
* 初始化供应者
* @param configuration The configuration
* @throws ConfigurationException If anything goes wrong
*/
public void init(Configuration configuration) throws ConfigurationException; /**
* 是否需要重新加载
*
* @return <tt>true</tt>, whether the ContainerProvider should reload its configuration, <tt>false</tt>otherwise.
*/
public boolean needsReload(); /**
* 用于注入容器的方法
*
* @param builder The builder to register beans with
* @param props The properties to register constants with
* @throws ConfigurationException If anything goes wrong
*/
public void register(ContainerBuilder builder, LocatableProperties props) throws ConfigurationException; }
上面代码里面的ContainerProvider就是所有供应者类的父类接口类之一。从上面代码就是可以看出来他的作用就是为Container容器服务的。其中register方法就是最明显的代表了。即是把信息注入到Container容器。好了。让笔者好好整理一下。struts2执行之前都做了一些什么工作。即是StrutsPrepareFilter类在Dispatcher类的帮助下做了些什么。如下。
1.判断ConfigurationManager类是否存在,如果不存在就是创建。
2.初始化文件管理类的供应者,并增加ConfigurationManager实例中。用于监督和管理加载的文件。
3.初始化加载default.properties文件信息的供应者,并增加ConfigurationManager实例中。用于加载struts2包default.properties信息。
4.初始化struts-default.xml,struts-plugin.xml,struts.xml信息的供应者,并增加ConfigurationManager实例中。用于加载struts2包中的struts-default.xml,struts-plugin.xml,struts.xml信息。
5.初始化struts.properties信息的供应者,并增加ConfigurationManager实例中。这里笔者也有一点奇怪。源码里面是去加载struts.properties信息。可是笔者一直没有找到对应的文件。
6.初始化用户传入的过滤器参数信息的供应者,并增加ConfigurationManager实例中。即是把过滤器参数一块注入到Container容器里面。
7.初始化struts-default.xml,struts-plugin.xml,struts.xml进行别名信息的供应者。用于加载struts2包中的struts-default.xml,struts-plugin.xml,struts.xml信息。只是这里用别名进行注入。
8.创建Container容器。把以上所有的供应者所提供的信息全部注入到Container容器。即是对象,常量等信息。
9.给Dispatcher类本身进行依赖注入。笔者相信读者会看Dispatcher类的方法上面有几个@Inject的关键字。没有错。这就是说明当前方法是用于依赖注入的。用Container类的inject方法就是注入的意思。
10.判断是否存在Dispatcher监听。如果存在就是执行。
11.初始化错误处理类。
| 本章总结 |
本章重点讲的是struts2启动的时候需要加载的相关工作。这些工作大部分是靠Dispatcher类来完成。所以StrutsPrepareFilter类的代码中有Dispatcher类的出现。最后会作为PrepareOperations类的构造参数存放起来。以备request请求处理的需要做准备。下一章笔者将会讲到。通过本章的讲解我们就会明白Dispatcher类在整个strtus2中起到了重要的中间调度的作用。
Struts2 源码分析——调结者(Dispatcher)之准备工作的更多相关文章
- Struts2 源码分析——调结者(Dispatcher)之执行action
章节简言 上一章笔者写关于Dispatcher类如何处理接受来的request请求.当然读者们也知道他并非正真的执行action操作.他只是在执行action操作之前的准备工作.那么谁才是正真的执行a ...
- Struts2 源码分析——调结者(Dispatcher)之action请求
章节简言 上一章笔者讲到关于struts2启动的时候加载对应的准备工作.如加载配置文件struts.xml之类的信息.而相应的这些操作都离不开Dispatcher类的帮助.如果读者只是认为Dispat ...
- Struts2 源码分析——配置管理之ContainerProvider接口
本章简言 上一章笔者讲到关于Dispatcher类的执行action功能,知道了关于执行action需要用到的信息.而本章将会讲到的内容也跟Dispatcher类有关系.那就是配置管理中的Contai ...
- Struts2 源码分析——Action代理类的工作
章节简言 上一章笔者讲到关于如何加载配置文件里面的package元素节点信息.相信读者到这里心里面对struts2在启动的时候加载相关的信息有了一定的了解和认识.而本章将讲到关于struts2启动成功 ...
- Struts2 源码分析——过滤器(Filter)
章节简言 上一章笔者试着建一个Hello world的例子.是一个空白的struts2例子.明白了运行struts2至少需要用到哪一些Jar包.而这一章笔者将根据前面章节(Struts2 源码分析—— ...
- Struts2 源码分析——配置管理之PackageProvider接口
本章简言 上一章讲到关于ContainerProvider的知识.让我们知道struts2是如何注册相关的数据.也知道如何加载相关的配置信息.本章笔者将讲到如何加载配置文件里面的package元素节点 ...
- Struts2 源码分析——Hello world
新建第一个应用程序 上一章我们讲到了关于struts2核心机制.对于程序员来讲比较概念的一章.而本章笔者将会亲手写一个Hello world的例子.所以如果对struts2使用比较了解的朋友,请跳过本 ...
- Struts2 源码分析——DefaultActionInvocation类的执行action
本章简言 上一章讲到关于拦截器的机制的知识点,让我们对拦截器有了一定的认识.我们也清楚的知道在执行用户action类实例之前,struts2会先去执行当前action类对应的拦截器.而关于在哪里执行a ...
- Struts2 源码分析——拦截器的机制
本章简言 上一章讲到关于action代理类的工作.即是如何去找对应的action配置信息,并执行action类的实例.而这一章笔者将讲到在执行action需要用到的拦截器.为什么要讲拦截器呢?可以这样 ...
随机推荐
- Linux之源码包安装软件
安装准备 安装c语言编辑器 gcc 压缩包 node-v6.2.0-linux-x64.tar.gz 源码包保存位置 /usr/local/src/ 源码包安装位置 /us ...
- 在Ubuntu13.04中配置Jexus+Mono3.2运行Asp.Net Mvc 4站点 (二)
开始写这篇前看了看日期,写下这个序列的前一半竟是两个月前的事情了,无比惭愧.这段时间尝试重新组织Mvc4的项目引用,创建了两个项目模板,一个是简单模式,即仅包含Mvc基本功能.另一个是包含了Mvc4 ...
- 使用knockout-sortable实现对自定义菜单的拖拽排序
在开始之前,照例,我们先看效果和功能实现. 关于自定义菜单的实现,这里就不多说了,需要了解的请访问:http://www.cnblogs.com/codelove/p/4838766.html 这里需 ...
- 强大好用的"文本"编辑器
1 editplugs 说明:EditPlus是一款由韩国 Sangil Kim (ES-Computing)出品的小巧但是功能强大的可处理文本.HTML和程序语言的Windows编辑器,你甚至可以通 ...
- Linux下添加新硬盘,分区及挂载(转)
挂载好新硬盘后输入fdisk -l命令看当前磁盘信息,卸载硬盘分区 umount /dev/sdb 可以看到除了当前的第一块硬盘外还有一块sdb的第二块硬盘,然后用fdisk /dev/sdb 进行分 ...
- 【源码分享】WPF漂亮界面框架实现原理分析及源码分享
1 源码下载 2 OSGi.NET插件应用架构概述 3 漂亮界面框架原理概述 4 漂亮界面框架实现 4.1 主程序 4.2 主程序与插件的通讯 4.2.1 主程序获取插件注册的服务 4.2 ...
- Emberjs之ComputedProperty
计算属性,以下简称CP.简单概括来讲,就是在需要属性值的时候计算一个Function,并将Function返回的值保存在属性中,当第二次获取属性值时,如果发现属性并未改变则直接读取属性,如果属性依赖的 ...
- ENode 2.0 - 深入分析ENode的内部实现流程和关键地方的幂等设计
前言 ENode是一个基于消息的架构,使用ENode开发的系统,每个环节都是处理消息,处理完后产生新的消息.本篇文章我想详细分析一下ENode框架内部是如何实现整个消息处理流程的.为了更好的理解我后面 ...
- dojo/dom-class源码学习
dom-class模块是dojo中对于一个元素class特性的操作(特性与属性的区别),主要方法有: contains 判断元素是否包含某个css class add 为元素添加某个css class ...
- web前端工程师在移动互联网时代里的地位问题
支付宝十周年推出了一个新产品:支付宝的十年账单,我也赶个时髦查看了一下我的支付宝十年账单,哎,感慨自己真是太屌丝了,不过这只是说明我使用淘宝少了,当我大规模网上购物时候,我很讨厌慢速的快递,所以我大部 ...