本文绝对原创,呕心沥血读了2天, 欢迎大家转载, 但是请朋友们尊重一下劳动成果,转载请注明出处
http://blog.csdn.net/izard999/article/details/40143439
在面试的时候,很多人经常会被问到:Struts2与Struts1的区别..我只想说, 最根本的区别是Struts2基于Filter,Struts1基于Servlet, 在Web容器中, Filter的优先级是高于Servlet的
那么上一篇文章中, 我给大家呈现那个官方的大图上面有个FilterDispatcher, 没错. 它就是Struts2的核心过滤器. 但是后来被遗弃
Deprecated. Since Struts 2.1.3, use StrutsPrepareAndExecuteFilter instead or StrutsPrepareFilter and StrutsExecuteFilter if needing using the ActionContextCleanUp filter in addition to this one
为什么遗弃我之前有所提到. 所以下面会研究StrutsPrepareAndExecuteFilter , 而不会再提及FilterDispatcher了.
在web.xml中我们指定Struts2的Filter为:
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
从这里看得出来, Struts2官方起名字还是挺有意思的.. ng是什么.? ng是next generation的缩写, 下一代产品
下面正题开始, StrutsPrepareAndExecuteFilter源码剖析, 有三个属性:
protected PrepareOperations prepare; //准备的一些操作
protected ExecuteOperations execute; //执行的一些操作
protected List<Pattern> excludedPatterns; //排斥的一些匹配路径
StrutsPrepareAndExecuteFilter与普通的Filter并无区别,方法除继承自Filter外,仅有一个回调方法,我们将按照Filter方法调用顺序,由init—>doFilter—>destroy顺序地分析源码。
1、init()
public void init(FilterConfig filterConfig) throws ServletException {
InitOperations init = new InitOperations();
Dispatcher dispatcher = null;
try {
<span style="white-space:pre"> </span> //封装filterConfig,其中有个主要方法getInitParameterNames将参数名字以String格式存储在List中
FilterHostConfig config = new FilterHostConfig(filterConfig);
// 初始化struts内部日志
init.initLogging(config);
//创建dispatcher ,并初始化,这部分下面我们重点分析,初始化时加载哪些些资源
dispatcher = init.initDispatcher(config);
// 初始化静态资源(静态资源后面会有讲解)
init.initStaticContentLoader(config, dispatcher);
//初始化类属性:prepare 、execute
prepare = new PrepareOperations(filterConfig.getServletContext(), dispatcher);
execute = new ExecuteOperations(filterConfig.getServletContext(), dispatcher);
//创建排斥路径列表
this.excludedPatterns = init.buildExcludedPatternsList(dispatcher);
//回调空的postInit方法
postInit(dispatcher, filterConfig);
} finally {
if (dispatcher != null) {
dispatcher.cleanUpAfterInit();
}
init.cleanup();
}
}
首先看下FilterHostConfig ,源码如下:
/**
* Host configuration that wraps FilterConfig
*/
public class FilterHostConfig implements HostConfig {
private FilterConfig config;
public FilterHostConfig(FilterConfig config) {
this.config = config;
}
/**
* 根据init-param配置的param-name获取param-value的值
*/
public String getInitParameter(String key) {
return config.getInitParameter(key);
}
/**
* 返回初始化参数名的List
*/
public Iterator<String> getInitParameterNames() {
return MakeIterator.convert(config.getInitParameterNames());
}
public ServletContext getServletContext() {
return config.getServletContext();
}
}
只有短短的几行代码,getInitParameterNames是这个类的核心,将Filter初始化参数名称有枚举类型转为Iterator。此类的主要作为是对filterConfig 封装。
public Dispatcher initDispatcher( HostConfig filterConfig ) {
Dispatcher dispatcher = createDispatcher(filterConfig);
dispatcher.init();
return dispatcher;
}
创建Dispatcher,会读取 filterConfig 中的配置信息,将配置信息解析出来,封装成为一个Map,然后根据ServletContext和参数Map构造Dispatcher :
private Dispatcher createDispatcher( HostConfig filterConfig ) {
Map<String, String> params = new HashMap<String, String>();
for ( Iterator e = filterConfig.getInitParameterNames(); e.hasNext(); ) {
String name = (String) e.next();
String value = filterConfig.getInitParameter(name);
params.put(name, value);
}
return new Dispatcher(filterConfig.getServletContext(), params);
}
</pre><pre name="code" class="java">/**
*初始化过程中依次加载如下配置文件
*/
public void init() {
if (configurationManager == null) {
configurationManager = new ConfigurationManager(BeanSelectionProvider.DEFAULT_BEAN_NAME);
}
try {
//加载org/apache/struts2/default.properties
init_DefaultProperties(); // [1]
//加载struts-default.xml,struts-plugin.xml,struts.xml
init_TraditionalXmlConfigurations(); // [2]
init_LegacyStrutsProperties(); // [3]
//用户自己实现的ConfigurationProviders类
init_CustomConfigurationProviders(); // [5]
//Filter的初始化参数
init_FilterInitParameters() ; // [6]
init_AliasStandardObjects() ; // [7]
Container container = init_PreloadConfiguration();
container.inject(this);
init_CheckConfigurationReloading(container);
init_CheckWebLogicWorkaround(container);
if (!dispatcherList