朝花夕拾之Struts2的StrutsPrepareAndExecuteFilter的初始化过程
在使用Struts2的时候,我们都会在项目中的web.xml这样定义:
<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>
这样写的意思是让所有的请求都经过这个过滤器(如果不想所有的请求都经过该过滤器,只需要更改url-pattern)。
而在早期的Struts2(2.1.0-2.1.3)的时候,并不是使用的StrutsPrepareAndExecuteFilter这个过滤器,而是使用FilterDispather,那么他们有什么区别呢?
<filter> <filter-name>struts2</filter-name> <filter-class> org.apache.struts2.dispatcher.FilterDispatcher </filter-class> </filter>
应该知道如果我们自己定义过滤器的话, 是要放在strtus2的过滤器之前的, 如果放在struts2过滤器之后,你自己的过滤器对action的过滤作用就废了,不会有效!除非你是访问jsp/html!
那我现在有需求, 我必须使用Action的环境,而又想在执行action之前拿filter做一些事, 用FilterDispatcher是做不到的.!
那么StrutsPrepareAndExecuteFilter可以把他拆分成StrutsPrepareFilter和StrutsExecuteFilter,可以在这两个过滤器之间加上我们自己的过滤器.!
我们来看一下StrutsPrepareAndExecuteFilter这个类:
void init(FilterConfig filterConfig) //继承自Filter,过滤器的初始化 void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) //继承自Filter 执行过滤器 void destory() //继承Filter
postInit(dispatcher, filterConfig); //回掉方法
在web容器一启动,就会去执行init方法:
public void init(FilterConfig filterConfig) throws ServletException { InitOperations init = new InitOperations(); Dispatcher dispatcher = null; try { //封装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用来将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); } //返回初始化参数名的迭代器 public Iterator<String> getInitParameterNames() { return MakeIterator.convert(config.getInitParameterNames()); } //返回Servlet上下文 public ServletContext getServletContext() { return config.getServletContext(); } }
getInitParameterNames()是这个类的核心方法,将Filter初始化参数名称有枚举类型转为Iterator。此类的主要作为是对filterConfig 封装。
看下StrutsPrepareAndExecuteFilter中init方法中dispatcher = init.initDispatcher(config);这是初始化dispatcher的,是通过init对象的initDispatcher方法来初始化的,init是InitOperations类的对象,我们看看InitOperations中initDispatcher方法:
public Dispatcher initDispatcher( HostConfig filterConfig ) { Dispatcher dispatcher = createDispatcher(filterConfig); dispatcher.init(); return dispatcher; }
private Dispatcher createDispatcher( HostConfig filterConfig ) { //存放参数的Map Map<String, String> params = new HashMap<String, String>(); //将参数存放到Map for ( Iterator e = filterConfig.getInitParameterNames(); e.hasNext(); ) { String name = (String) e.next(); String value = filterConfig.getInitParameter(name); params.put(name, value); } //根据servlet上下文和参数Map构造Dispatcher return new Dispatcher(filterConfig.getServletContext(), params); }
这样dispatcher对象创建完成,接着就是dispatcher对象的初始化,打开Dispatcher类,看到它的init方法如下:
public void init() { if (configurationManager == null) { configurationManager = createConfigurationManager(BeanSelectionProvider.DEFAULT_BEAN_NAME); } try { init_FileManager(); //加载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_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); } }
这里主要是加载一些配置文件的,将按照顺序逐一加载:default.properties,struts-default.xml,struts-plugin.xml,struts.xml,……关于文件是如何加载的,大家可以自己取看源文件,主要是由xwork核心类加载的,代码在xwork-core\src\main\java\com\opensymphony\xwork2\config\providers包里面。