Struts2源码分析 初步2Dispatcher初始化细节(1)

Struts2 源码初步学习—Dispatcher初始化细节

先贴代码

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

/**

 * Load configurations, including both XML and zero-configuration strategies,

 * and update optional settings, including whether to reload configurations and resource files.

 */

publicvoidinit() {

 

    if(configurationManager == null) {

        configurationManager = newConfigurationManager(BeanSelectionProvider.DEFAULT_BEAN_NAME);

    }

 

    try{

        init_DefaultProperties(); // [1]

        init_TraditionalXmlConfigurations(); // [2]

        init_LegacyStrutsProperties(); // [3]

        init_CustomConfigurationProviders(); // [5]

        init_FilterInitParameters() ; // [6]

        init_AliasStandardObjects() ; // [7]

 

        Container container = init_PreloadConfiguration();

        container.inject(this);

        init_CheckConfigurationReloading(container);

        init_CheckWebLogicWorkaround(container);

 

        if(!dispatcherListeners.isEmpty()) {

            for(DispatcherListener l : dispatcherListeners) {

                l.dispatcherInitialized(this);

            }

        }

    } catch(Exception ex) {

        if(LOG.isErrorEnabled())

            LOG.error("Dispatcher initialization failed", ex);

        thrownewStrutsException(ex);

    }

}

这些小的初始化方法

都会用到ConfigurationManager这个类的对象。这个类是xwork的配置管理类。

这个类中涉及两个基础知识ReentrantLock CopyOnWriteArrayList类,详细说明参见JDK

并注意ReentrantLock基本用法 参见方法 public List<ContainerProvider> getContainerProviders()

在方法一开始出lock上,在方法的最后finally部分unlock

看下方法体

providerLock.lock();

try {

if (containerProviders.size() == 0) {

containerProviders.add(new XWorkConfigurationProvider());

containerProviders.add(new XmlConfigurationProvider("xwork.xml", false));

}

 

returncontainerProviders;

} finally {

providerLock.unlock();

}

同时这个类中会主要涉及ContainerProvider这个类

上面是ContainerProvider接口的实现结构

可以看出struts(xwork)几乎未每种配置做了provider

看下这个接口定义的方法如下:

这个接口主要要实现register方法,其中有个参数是ContainerBuilder,这个接口是ContainerProvider,都跟Container有关,别着急,我后面会专门写一篇介绍struts容器的。当然我们在这边关心的不是其register方法,而是init方法,毕竟这篇文章是分析的Dispatcherinit细节

这个ConfigurationManager有个addContainerProvider方法,主要是用来维护属性

private List<ContainerProvider> containerProviders = new CopyOnWriteArrayList<ContainerProvider>();

每当调用一个不同的init方法时,便会用几乎不同的ContainerProviderso这个属性就是用来持有这些provider的列表

 

不难发现对于类Dispatcher来说是在init方法一开始处初始化

if (configurationManager == null) {

configurationManager = new ConfigurationManager(BeanSelectionProvider.DEFAULT_BEAN_NAME);

}

下面逐一分析那几个init方法

init_DefaultProperties 方法很简单 就是把DefaultPropertiesProvider加进上面所说的类ConfigurationManagercontainerProviders (是个列表)属性,当然从上面的图不难发现DefaultPropertiesProvider实现了ContainerProvider接口

init_TraditionalXmlConfigurations这个方法也简单,

先是从初始化参数中读取有没有配置config这个参数,若没有,default配置文件则用默认的privatestaticfinal String DEFAULT_CONFIGURATION_PATHS = "struts-default.xml,struts-plugin.xml,struts.xml";

然后根据这些文件名字的不同做一些特殊处理

xwork.xml的用XmlConfigurationProvider

其他的用StrutsXmlConfigurationProvide

当然仍然是将这些provider加进上面所说的类ConfigurationManagercontainerProviders (是个列表)属性。只是这两个provider的构造方法做了点事情。上面的DefaultPropertiesProvider的构造方法根本没有显式声明

看下StrutsXmlConfigurationProvide的构造方法做了啥?

贴下代码一目明了

super(filename, errorIfMissing);

this.servletContext = ctx;

this.filename = filename;

reloadKey = "configurationReload-"+filename;

Map<String,String> dtdMappings = new HashMap<String,String>(getDtdMappings());

dtdMappings.put("-//Apache Software Foundation//DTD Struts Configuration 2.0//EN", "struts-2.0.dtd");

dtdMappings.put("-//Apache Software Foundation//DTD Struts Configuration 2.1//EN", "struts-2.1.dtd");

dtdMappings.put("-//Apache Software Foundation//DTD Struts Configuration 2.1.7//EN", "struts-2.1.7.dtd");

setDtdMappings(dtdMappings);

File file = new File(filename);

if (file.getParent() != null) {

this.baseDir = file.getParentFile();

}

setDtdMappings 是为后面解析这些配置文件做校验用的。

  1. init_LegacyStrutsProperties 这个个初始化也没做什么事 对应的providerLegacyPropertiesConfigurationProvider

  1. init_CustomConfigurationProviders 初始化init参数中自定义的(如果有)ConfigurationProvider

  1. init_FilterInitParameters 这个初始化方法中ConfigurationManagercontainerProviders列表中加入一个内部类 new ConfigurationProvider() {…} 这个providerinit方法没做什么事 register方法倒是做了点事情

  2. init_AliasStandardObjects beanSelectionProvider 放进了ConfigurationManagercontainerProviders列表中

  3. init_PreloadConfiguration 初始化容器 这个方法很关键。做了很多事情。包括加载配置文件 包括初始化容器 here --> reloadContainer-->createBootStrap等等。F3跟进去看下,看不出来啥。还要再跟一层,主要是Configuration config = configurationManager.getConfiguration();

    configurationManager类的getConfiguration()方法

    configuration.reloadContainer(getContainerProviders());

    分析 reloadContainer方法,传进来的参数就是上面几步初始化一直在维护的containerProviders(provider列表)

    reloadContainer方法迭代这个provider列表做了两件事情 就是调用每个providerinitregister方法,其实在ContainerProvider接口中能看到定义了这样的方法

    containerProvider.init(this);

    containerProvider.register(builder, props); 这个register方法牵扯到的两个参数,ContainerBuilderContainerProperties两个类的对象,这两个类的对象都是在这个方法体中直接new出来的。

    ContainerProperties props = new ContainerProperties();

    ContainerBuilder builder = new ContainerBuilder();

    ContainerBuilder 的构造方法中将默认两种必要的工厂加到builder的属性final Map<Key<?>, InternalFactory<?>> factories 中。这两中必要的工厂分别是日志工厂和容器工厂。

    这边涉及到接口 InternalFactory 注释为 “ 创建那些将被注入的对象” 。只定义了一个方法

    T create(InternalContext context); 就是创建工厂中的产品。

    这个下面牵扯到的类就相对多点 写法相对绕点了

    <T> InternalFactory<? extends T> scopeFactory(Class<T> type, String name,

    InternalFactory<? extends T> factory) {

    return factory;

未完待续

原文地址:https://www.cnblogs.com/simoncook/p/2266935.html