struts2源码分析之配置文件加载顺序

本次源码分析的目标:

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

引言

问题的引出是由于前些天在oschina上看到的一篇帖子,http://www.oschina.net/question/593078_105422,截图如下:

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

分析

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

01

<filter>

02

<filter-name>struts2</filter-name>

03

<filter-class>

04

org.apache.struts2.dispatcher.FilterDispatcher

05

</filter-class>

06

</filter>

07

<filter-mapping>

08

<filter-name>struts2</filter-name>

09

<url-pattern>/*</url-pattern>

10

</filter-mapping>

从上述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,方便查看分析。待一切准备工作就绪后,我们进行具体的分析工作。

01

/**

02

*Initializesthefilterbycreatingadefaultdispatcher

03

*andsettingthedefaultpackagesforstaticresources.

04

*

05

*@paramfilterConfigThefilterconfiguration

06

*/

07

publicvoidinit(FilterConfigfilterConfig)throwsServletException{

08

try{

09

this.filterConfig=filterConfig;

10

11

initLogging();

12

13

dispatcher=createDispatcher(filterConfig);

14

dispatcher.init();

15

dispatcher.getContainer().inject(this);

16

17

staticResourceLoader.setHostConfig(newFilterHostConfig(filterConfig));

18

}finally{

19

ActionContext.setContext(null);

20

}

21

}

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

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

01

/**

02

*Loadconfigurations,includingbothXMLandzero-configurationstrategies,

03

*andupdateoptionalsettings,includingwhethertoreloadconfigurationsandresourcefiles.

04

*/

05

publicvoidinit(){

06

07

if(configurationManager==null){

08

configurationManager=createConfigurationManager(BeanSelectionProvider.DEFAULT_BEAN_NAME);

09

}

10

11

try{

12

init_FileManager();

13

init_DefaultProperties();//[1]

14

init_TraditionalXmlConfigurations();//[2]

15

init_LegacyStrutsProperties();//[3]

16

init_CustomConfigurationProviders();//[5]

17

init_FilterInitParameters();//[6]

18

init_AliasStandardObjects();//[7]

19

20

Containercontainer=init_PreloadConfiguration();

21

container.inject(this);

22

init_CheckWebLogicWorkaround(container);

23

24

if(!dispatcherListeners.isEmpty()){

25

for(DispatcherListenerl:dispatcherListeners){

26

l.dispatcherInitialized(this);

27

}

28

}

29

}catch(Exceptionex){

30

if(LOG.isErrorEnabled())

31

LOG.error("Dispatcherinitializationfailed",ex);

32

thrownewStrutsException(ex);

33

}

34

}

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

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

1

privatevoidinit_DefaultProperties(){

2

configurationManager.addContainerProvider(newDefaultPropertiesProvider());

3

}

01

/**

02

*Loadsthedefaultproperties,separatefromtheusualstruts.propertiesloading

03

*/

04

publicclassDefaultPropertiesProviderextendsLegacyPropertiesConfigurationProvider{

05

06

publicvoiddestroy(){

07

}

08

09

publicvoidinit(Configurationconfiguration)throwsConfigurationException{

10

}

11

12

publicvoidregister(ContainerBuilderbuilder,LocatablePropertiesprops)

13

throwsConfigurationException{

14

15

SettingsdefaultSettings=null;

16

try{

17

defaultSettings=newPropertiesSettings("org/apache/struts2/default");

18

}catch(Exceptione){

19

thrownewConfigurationException("Couldnotfindorerrorinorg/apache/struts2/default.properties",e);

20

}

21

22

loadSettings(props,defaultSettings);

23

}

24

25

}

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

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

01

privatevoidinit_TraditionalXmlConfigurations(){

02

StringconfigPaths=initParams.get("config");

03

if(configPaths==null){

04

configPaths=DEFAULT_CONFIGURATION_PATHS;

05

}

06

String[]files=configPaths.split("\\s*[,]\\s*");

07

for(Stringfile:files){

08

if(file.endsWith(".xml")){

09

if("xwork.xml".equals(file)){

10

configurationManager.addContainerProvider(createXmlConfigurationProvider(file,false));

11

}else{

12

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

13

}

14

}else{

15

thrownewIllegalArgumentException("Invalidconfigurationfilename");

16

}

17

}

18

}

1

/**

2

*Providelistofdefaultconfigurationfiles.

3

*/

4

privatestaticfinalStringDEFAULT_CONFIGURATION_PATHS="struts-default.xml,struts-plugin.xml,struts.xml";

上述函数的处理流程是:

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

1

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

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

1

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

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

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

1

privatevoidinit_LegacyStrutsProperties(){

2

configurationManager.addContainerProvider(newLegacyPropertiesConfigurationProvider());

3

}

01

//SetdefaultlocalebylazilyresolvingthelocalepropertyasneededintoaLocaleobject

02

builder.factory(Locale.class,newFactory(){

03

privateLocalelocale;

04

05

publicsynchronizedObjectcreate(Contextcontext)throwsException{

06

if(locale==null){

07

Stringloc=context.getContainer().getInstance(String.class,StrutsConstants.STRUTS_LOCALE);

08

if(loc!=null){

09

StringTokenizerlocaleTokens=newStringTokenizer(loc,"_");

10

Stringlang=null;

11

Stringcountry=null;

12

13

if(localeTokens.hasMoreTokens()){

14

lang=localeTokens.nextToken();

15

}

16

17

if(localeTokens.hasMoreTokens()){

18

country=localeTokens.nextToken();

19

}

20

locale=newLocale(lang,country);

21

}else{

22

if(LOG.isInfoEnabled()){

23

LOG.info("Nolocaledefine,substitutingthedefaultVMlocale");

24

}

25

locale=Locale.getDefault();

26

}

27

}

28

returnlocale;

29

}

30

});

1

/**ThedefaultlocalefortheStrutsapplication*/

2

publicstaticfinalStringSTRUTS_LOCALE="struts.locale";

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

总结

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

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

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

相关推荐