博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
struts2源码分析之配置文件加载顺序
阅读量:6344 次
发布时间:2019-06-22

本文共 7446 字,大约阅读时间需要 24 分钟。

  hot3.png

本次源码分析的目标:

弄清struts2加载各配置文件的顺序,得到此配置文件加载顺序,则源码分析任务结束。

引言

问题的引出是由于前些天在oschina上看到的一篇帖子,,截图如下:

带着这样的一个问题,我们尝试从struts2源码的角度去解答。

分析

要想弄清struts2的配置文件加载顺序问题,首先我们必须要知道struts2的入口在什么地方?

    
struts2
    
        org.apache.struts2.dispatcher.FilterDispatcher                
    
struts2
    
/*

从上述web.xml的filter节中,我们可以看到struts2是在filter中定义了一个FilterDispatcher,用来拦截符合在filter-mapping中定义的url-pattern的所有url请求,然后将拦截到的url请求交给该FilterDispather处理,所以接下来我们将重点分析该filter,既然是一个过滤器,那么最重要的方法莫过于三个,分别是init(),doFilter(),destroy(),从三个方法的名称结合我们本次源码分析的任务,我们将重点分析init()方法,顾名思义,该方法进行struts2的初始化工作。

经过上述的简单思考,我们接下来将进行具体的源码分析工作。

源码分析

和之前的源码分析工作一样,首先还是先下载struts2源码(版本为struts-2.3.12),然后将其导入eclipse,方便查看分析。待一切准备工作就绪后,我们进行具体的分析工作。

 

   /**     * Initializes the filter by creating a default dispatcher     * and setting the default packages for static resources.     *     * @param filterConfig The filter configuration     */    public void init(FilterConfig filterConfig) throws ServletException {        try {            this.filterConfig = filterConfig;            initLogging();            dispatcher = createDispatcher(filterConfig);            dispatcher.init();            dispatcher.getContainer().inject(this);            staticResourceLoader.setHostConfig(new FilterHostConfig(filterConfig));        } finally {            ActionContext.setContext(null);        }    }

从init()函数上面的注释可以看到,该方法是通过创建一个默认的dispatcher和设置默认的静态资源包来初始化该过滤器。

从上述具体的处理流程我们可以看到,所有的初始化工作,应该都是在dispachter.init()方法中,所以接下来将重点分析该方法。

    /**     * Load configurations, including both XML and zero-configuration strategies,     * and update optional settings, including whether to reload configurations and resource files.     */    public void init() {    	if (configurationManager == null) {    		configurationManager = createConfigurationManager(BeanSelectionProvider.DEFAULT_BEAN_NAME);    	}        try {            init_FileManager();            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_CheckWebLogicWorkaround(container);            if (!dispatcherListeners.isEmpty()) {                for (DispatcherListener l : dispatcherListeners) {                    l.dispatcherInitialized(this);                }            }        } catch (Exception ex) {            if (LOG.isErrorEnabled())                LOG.error("Dispatcher initialization failed", ex);            throw new StrutsException(ex);        }    }

 

从该函数的注释头部分我们可以看到,该方法是加载配置信息并更新可选择的配置(某些配置信息,虽然在前面已经配置了,但还是可以在后面的配置文件中对其进行覆盖操作)。从上述七个init_*函数,与我们本次源码分析目标相关的函数应该是init_DefaultProperties()、init_TraditionalXmlConfigurations()以及init_LegacyStrutsProperties(),接下来我们将一个个的加以分析:

首先是init_DefaultProperties(),该函数定义如下:

 private void init_DefaultProperties() {        configurationManager.addContainerProvider(new DefaultPropertiesProvider());    }

 

/** * Loads the default properties, separate from the usual struts.properties loading */public class DefaultPropertiesProvider extends LegacyPropertiesConfigurationProvider {    public void destroy() {    }    public void init(Configuration configuration) throws ConfigurationException {    }    public void register(ContainerBuilder builder, LocatableProperties props)            throws ConfigurationException {                Settings defaultSettings = null;        try {            defaultSettings = new PropertiesSettings("org/apache/struts2/default");        } catch (Exception e) {            throw new ConfigurationException("Could not find or error in org/apache/struts2/default.properties", e);        }                loadSettings(props, defaultSettings);    }}

以上可以看到,其处理的配置文件是:org/apache/struts2/default.properties

其次是init_TraditionalXmlConfigurations(),该函数定义如下:

 

    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");            }        }    }

 

 /**     * Provide list of default configuration files.     */    private static final String DEFAULT_CONFIGURATION_PATHS = "struts-default.xml,struts-plugin.xml,struts.xml";

 

上述函数的处理流程是:

如果configPaths为Null,则使用其默认值

"struts-default.xml,struts-plugin.xml,struts.xml"

 

然后根据[,]进行分割,得到三个文件名:struts-default.xml, struts-plugin.xml, struts.xml,并以此对这三个文件进行处理,如果文件名以*.xml结尾且不是xwork.xml,则调用函数

configurationManager.addContainerProvider(createStrutsXmlConfigurationProvider(file, false, servletContext));

从上述可以看到,所谓的struts-*.xml配置文件处理顺序,其实就是变量DEFAULT_CONFIGURATION_PATHS中,字符串定义的顺序。

最后一个函数是init_LegacyStrutsProperties(),从函数名,我们可以简单的判断出,该函数是处理遗留下来的struts配置文件,其定义如下:

    private void init_LegacyStrutsProperties() {        configurationManager.addContainerProvider(new LegacyPropertiesConfigurationProvider());    }

 

       // Set default locale by lazily resolving the locale property as needed into a Locale object        builder.factory(Locale.class, new Factory() {            private Locale locale;            public synchronized Object create(Context context) throws Exception {                if (locale == null) {                    String loc = context.getContainer().getInstance(String.class, StrutsConstants.STRUTS_LOCALE);                    if (loc != null) {                        StringTokenizer localeTokens = new StringTokenizer(loc, "_");                        String lang = null;                        String country = null;                        if (localeTokens.hasMoreTokens()) {                            lang = localeTokens.nextToken();                        }                        if (localeTokens.hasMoreTokens()) {                            country = localeTokens.nextToken();                        }                        locale = new Locale(lang, country);                    } else {                        if (LOG.isInfoEnabled()) {                            LOG.info("No locale define, substituting the default VM locale");                        }                        locale = Locale.getDefault();                    }                }                return locale;            }        });

 

   /** The default locale for the Struts application */    public static final String STRUTS_LOCALE = "struts.locale";

 

从上面的处理流程,我们可以看到,主要是加载配置文件struts.locale文件。

总结

从上述的源码分析,我们可以看到,struts2在处理配置文件的一个相对顺序为:

default.properties -> struts-default.xml -> struts-plugins.xml -> struts.xml -> struts.locale

请注意上述描述用词,是相对顺序,还有很多配置文件未列入,如果想了解更多的信息,可继续分析上述提到的init_*函数。 

如果您对算法或编程感兴趣,欢迎扫描下方二维码并关注公众号“算法与编程之美”,和您一起探索算法和编程的神秘之处,给您不一样的解题分析思路。

 

转载于:https://my.oschina.net/gschen/blog/121433

你可能感兴趣的文章
bootstrap随笔点击增加
查看>>
oracle 中proc和oci操作对缓存不同处理
查看>>
[LeetCode] Spiral Matrix 解题报告
查看>>
60906磁悬浮动力系统应用研究与模型搭建
查看>>
指纹获取 Fingerprint2
查看>>
SB阿里云,windows2012r2无法安装.net3.5
查看>>
函数的继承
查看>>
黑盒测试用例设计方法&理论结合实际 -> 场景法
查看>>
快速打开软件以及文件夹
查看>>
CSS选择符
查看>>
剑指offer---19--***-顺时针打印矩阵
查看>>
关于数组随机不重复的思路
查看>>
oracle赋值问题(将同一表中某一字段赋值给另外一个字段的语句)
查看>>
Windows 安装 Jenkins 2.6
查看>>
计算一个点是否在一个区域中
查看>>
正则表达式
查看>>
淘宝面试题:有一个一亿节点的树,现在已知两个点,找这两个点的共同的祖先。...
查看>>
EntityFramework 6.x多个上下文迁移实现分布式事务
查看>>
高版本SQL备份在低版本SQL还原问题
查看>>
一键安装最新内核并开启 BBR 脚本
查看>>