这一篇文章主要是记录struts.xml的初始化,还原struts2.xml的初始化流程。源码依据struts2-2.3.16.3版本。

  struts2初始化入口,位于web.xml中:

     <filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>

  调用StrutsPrepareAndExecuteFilterinit(FilterConfig filterConfig)方法,进行初始化:

public void init(FilterConfig filterConfig) throws ServletException {
InitOperations init = new InitOperations();
Dispatcher dispatcher = null;
try {
FilterHostConfig config = new FilterHostConfig(filterConfig);
init.initLogging(config);
dispatcher = init.initDispatcher(config);
init.initStaticContentLoader(config, dispatcher); prepare = new PrepareOperations(filterConfig.getServletContext(), dispatcher);
execute = new ExecuteOperations(filterConfig.getServletContext(), dispatcher);
this.excludedPatterns = init.buildExcludedPatternsList(dispatcher); postInit(dispatcher, filterConfig);
} finally {
if (dispatcher != null) {
dispatcher.cleanUpAfterInit();
}
init.cleanup();
}
}

  InitOperations定义了初始化的实现,提供struts2初始化的各个部件的构建过程,包括:logger、dispatcher、static content loader 。我们这里只关心dispatcher的初始化流程。

  dispather的init过程被分解了多个步骤:

            init_FileManager();
init_DefaultProperties(); // [1]
init_TraditionalXmlConfigurations(); // [2]//初始化struts.xml
init_LegacyStrutsProperties(); // [3]
init_CustomConfigurationProviders(); // [5]
init_FilterInitParameters() ; // [6]
init_AliasStandardObjects() ; // [7]

  其中第2个步骤:init_TraditionalXmlConfigurations();就是准备初始化xml文件的: 

   private void init_TraditionalXmlConfigurations() {
String configPaths = initParams.get("config");
if (configPaths == null) {
configPaths = DEFAULT_CONFIGURATION_PATHS;//DEFAULT_CONFIGURATION_PATHS = "struts-default.xml,struts-plugin.xml,struts.xml",即默认需要初始化这三个配置文件。
}
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");
}
}
}

  默认根据struts-default.xml,struts-plugin.xml,struts.xml (可根据init-param:config 修改加载路径) 分别创建三个 org.apache.struts2.config. StrutsXmlConfigurationProvider,其中方法register实现默认会从相应配置文件读取props加载到setting 中,会将bean放入ContainerBuilder中,最后将三个containerProviders并加入containerProviders。

  全部的providers准备好后,preLoad配置的时候就会把配置初始化出来:

     Container container = init_PreloadConfiguration();

  private Container init_PreloadConfiguration() {
Configuration config = configurationManager.getConfiguration();
Container container = config.getContainer(); boolean reloadi18n = Boolean.valueOf(container.getInstance(String.class, StrutsConstants.STRUTS_I18N_RELOAD));
LocalizedTextUtil.setReloadBundles(reloadi18n); ContainerHolder.store(container); return container;
}

  configurationManager.getConfiguration()的作用是根据配置将configuration对象实例化,并根据当前的container将内容填充:  

  public synchronized Configuration getConfiguration() {
if (configuration == null) {
setConfiguration(createConfiguration(defaultFrameworkBeanName));
try {
configuration.reloadContainer(getContainerProviders());
} catch (ConfigurationException e) {
setConfiguration(null);
throw new ConfigurationException("Unable to load configuration.", e);
}
} else {
conditionalReload();
} return configuration;
}

    调用每个providers的register方法解析制定的xml,此处的providers即包含前面在init_TraditionalXmlConfigurations中初始化的struts-default.xml,struts-plugin.xml,struts.xml的三个providers。

     public synchronized List<PackageProvider> reloadContainer(List<ContainerProvider> providers) throws ConfigurationException {
packageContexts.clear();
loadedFileNames.clear();
List<PackageProvider> packageProviders = new ArrayList<PackageProvider>(); ContainerProperties props = new ContainerProperties();
ContainerBuilder builder = new ContainerBuilder();
Container bootstrap = createBootstrapContainer(providers);
for (final ContainerProvider containerProvider : providers)
{
bootstrap.inject(containerProvider);
containerProvider.init(this);
containerProvider.register(builder, props);
}

  继续向下看StrutsXmlConfigurationProvider.register方法,可以看到关键逻辑是在父类里面:  

 StrutsXmlConfigurationProvider.java
public void register(ContainerBuilder containerBuilder, LocatableProperties props) throws ConfigurationException {
if (servletContext != null && !containerBuilder.contains(ServletContext.class)) {
containerBuilder.factory(ServletContext.class, new Factory<ServletContext>() {
public ServletContext create(Context context) throws Exception {
return servletContext;
}
});
}
super.register(containerBuilder, props);
}

   这里将在xml文件中定义的bean、contants、unknown-handler-stack 元素取出来并加载到容器中去。

 for (Document doc : documents) {
Element rootElement = doc.getDocumentElement();
NodeList children = rootElement.getChildNodes();
int childSize = children.getLength(); for (int i = 0; i < childSize; i++) {
Node childNode = children.item(i); if (childNode instanceof Element) {
Element child = (Element) childNode; final String nodeName = child.getNodeName(); if ("bean".equals(nodeName)) { } else if ("constant".equals(nodeName)) { } else if (nodeName.equals("unknown-handler-stack")) { }
}
}
}

  loadPackages负责初始化struts2 pacakge定义

  for (Document doc : documents) {
Element rootElement = doc.getDocumentElement();
NodeList children = rootElement.getChildNodes();
int childSize = children.getLength(); for (int i = 0; i < childSize; i++) {
Node childNode = children.item(i); if (childNode instanceof Element) {
Element child = (Element) childNode; final String nodeName = child.getNodeName(); if ("package".equals(nodeName)) {
PackageConfig cfg = addPackage(child);
if (cfg.isNeedsRefresh()) {
reloads.add(child);
}
}
}
}
loadExtraConfiguration(doc);
}

  

  

struts2源码分析-初始化流程的更多相关文章

  1. Struts2 源码分析——Action代理类的工作

    章节简言 上一章笔者讲到关于如何加载配置文件里面的package元素节点信息.相信读者到这里心里面对struts2在启动的时候加载相关的信息有了一定的了解和认识.而本章将讲到关于struts2启动成功 ...

  2. Struts2 源码分析——配置管理之PackageProvider接口

    本章简言 上一章讲到关于ContainerProvider的知识.让我们知道struts2是如何注册相关的数据.也知道如何加载相关的配置信息.本章笔者将讲到如何加载配置文件里面的package元素节点 ...

  3. Struts2 源码分析——配置管理之ContainerProvider接口

    本章简言 上一章笔者讲到关于Dispatcher类的执行action功能,知道了关于执行action需要用到的信息.而本章将会讲到的内容也跟Dispatcher类有关系.那就是配置管理中的Contai ...

  4. Struts2 源码分析——调结者(Dispatcher)之执行action

    章节简言 上一章笔者写关于Dispatcher类如何处理接受来的request请求.当然读者们也知道他并非正真的执行action操作.他只是在执行action操作之前的准备工作.那么谁才是正真的执行a ...

  5. Struts2 源码分析——过滤器(Filter)

    章节简言 上一章笔者试着建一个Hello world的例子.是一个空白的struts2例子.明白了运行struts2至少需要用到哪一些Jar包.而这一章笔者将根据前面章节(Struts2 源码分析—— ...

  6. Struts2 源码分析——DefaultActionInvocation类的执行action

    本章简言 上一章讲到关于拦截器的机制的知识点,让我们对拦截器有了一定的认识.我们也清楚的知道在执行用户action类实例之前,struts2会先去执行当前action类对应的拦截器.而关于在哪里执行a ...

  7. Struts2 源码分析——拦截器的机制

    本章简言 上一章讲到关于action代理类的工作.即是如何去找对应的action配置信息,并执行action类的实例.而这一章笔者将讲到在执行action需要用到的拦截器.为什么要讲拦截器呢?可以这样 ...

  8. Struts2 源码分析——Hello world

    新建第一个应用程序 上一章我们讲到了关于struts2核心机制.对于程序员来讲比较概念的一章.而本章笔者将会亲手写一个Hello world的例子.所以如果对struts2使用比较了解的朋友,请跳过本 ...

  9. apiserver源码分析——启动流程

    前言 apiserver是k8s控制面的一个组件,在众多组件中唯一一个对接etcd,对外暴露http服务的形式为k8s中各种资源提供增删改查等服务.它是RESTful风格,每个资源的URI都会形如 / ...

随机推荐

  1. Linux -- cal/bc/LANGE与帮助文档

    cal 显示日历命令 使用cal命令,显示日历 cal [month] [year] 1.显示当前的日历 [root@localhost ~]# cal 一月 日 一 二 三 四 五 六 2.显示指定 ...

  2. luajit 64位 for cocos2dx 编译ios解决方法

    最近luajit发布了64位beta版,由于appstore上线必须是64位的应用,而且我的游戏项目用到lua脚本,所以必须要用到64位的luajit来编译lua脚本. 方法如下: 在luajit官网 ...

  3. 丑数(Ugly Numbers, UVa 136)

    丑数(Ugly Numbers, UVa 136) 题目描述 我们把只包含因子2.3和5的数称作丑数(Ugly Number).求按从小到大的顺序的第1500个丑数.例如6.8都是丑数,但14不是,因 ...

  4. 剑指Offer_编程题之替换空格

    题目描述 请实现一个函数,将一个字符串中的空格替换成“%20”.例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy.

  5. MySQL常用参数说明(持续更新)

      ##innodb correlate   innodb_flush_log_at_trx_commit value: 0,[1],2 effect: control the flush opera ...

  6. 常用模块 - shutil模块

    一.简介 shutil – Utility functions for copying and archiving files and directory trees.(用于复制和存档文件和目录树的实 ...

  7. 配置一个nginx反向代理&负载均衡服务器

    一.基本信息 系统(L):CentOS 6.9 #下载地址:http://mirrors.sohu.com 反代&负载均衡(N):NGINX 1.14.0 #下载地址:http://nginx ...

  8. PHP文档生成器(PHPDoc)的基本用法

    目录 PHP文档生成器(PHPDoc)的基本用法 PHPDoc概述 安装 PHPDoc注释规范 页面级别的注释 代码级别的注释 生成API文档 额外软件 PHP文档生成器(PHPDoc)的基本用法 P ...

  9. Debian中CodeIgniter+nginx+MariaDB+phpMyAdmin配置

    本文不讲述软件安装过程,记述本人在Debia中配置CodeIgniter时遇到的问题及解决方法,希望能够为有需要的人提供帮助. 一.Debian版本及所需的软件 Debian 9.8 stretch ...

  10. tp js结合时间戳

    $(document).ready(function(){ $.extend({ show:function(){ } }); setInterval("show()",1000) ...