这一篇文章主要是记录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. python Web开发之 WSGI & uwsgi & uWSGI

    首先弄清下面几个概念: WSGI 全称是Web Server Gateway Interface,WSGI不是服务器,python模块,框架,API或者任何软件,只是一种规范,描述web server ...

  2. window下安装composer

    1.什么是composer 一个智能的下载工具.比如说我的项目要安装yii框架,而yii是依赖于其他东西的,仅仅安装yii是不够的,这样会导致我的项目也不能正常运行:怎么办呢,我们可以一个一个手动的将 ...

  3. 更新UI放在主线程的原因

    1.在子线程中是不能进行UI 更新的,而可以立刻更新的原因是:子线程代码执行完毕了,又自动进入到了主线程,这中间的时间非常的短,让我们误以为子线程可以更新UI.如果子线程一直在运行,则无法更新UI,因 ...

  4. Vue--- 一点车项目 连接数据库

    Vue--- 一点车项目  连接数据库 创建连接数据库配置 ###导入 const Koa = require('koa'); const Router = require('koa-router') ...

  5. Action与Func 用法

    //vs2017 + framework4.6.2 //zip    https://github.com/chxl800/ActionFuncDemo //源文件git   https://gith ...

  6. @Component注解、@Service注解、@Repository注解、@Controller注解区别

    --------------------------------------------------------------------------------------------------- ...

  7. ThinkPHP5.0框架事务处理操作简单示例

    本文介绍ThinkPHP5.0框架事务处理操作,结合实例形式分析了ThinkPHP5针对删除操作的事务处理相关操作技巧,可以加深对ThinkPHP源码的理解,需要的朋友可以参考下 事务的调用在mysq ...

  8. Python文本和字符串常用操作

    ## 字符串分割 line = "This is my love!" fields = line.split(' ') print(fields) # ['This', 'is', ...

  9. FireDAC的SQLite初探

    // uses FireDAC.VCLUI.Wait  之后, 可不用添加 TFDGUIxWaitCursor TFDConnection          // 数据连接 TFDQuery      ...

  10. Hadoop-Hive学习笔记(2)

    1.Hive基本操作 #创建数据库hive>create database name;#创建新表hive> create table students(id int,name string ...