朝花夕拾之Struts2的StrutsPrepareAndExecuteFilter的初始化过程

时间:2021-04-30 19:37:36

在使用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包里面。