Struts2中StrutsPrepareAndExecuteFilter源码浅析

Struts的前端控制器是StrutsPrepareAndExecuteFilter过滤器,这个过滤器和普通过滤器一样,主要有两个比较重要的方法:init(FilterConfig filterConfig)、doFilter(ServletRequest req, ServletResponse res, FilterChain chain)。下面就主要说一下这个两个方法具体做了什么事,

Init()方法详细步骤:

public void init(FilterConfig filterConfig) throws ServletException {
        InitOperations init = new InitOperations();
        Dispatcher dispatcher = null;
        try {
            FilterHostConfig config = new FilterHostConfig(filterConfig);
            init.initLogging(config);
            dispatcher = init.initDispatcher(config);
            init.initStaticContentLoader(config, dispatcher);

            prepare = new PrepareOperations(filterConfig.getServletContext(), dispatcher);
            execute = new ExecuteOperations(filterConfig.getServletContext(), dispatcher);
            this.excludedPatterns = init.buildExcludedPatternsList(dispatcher);

            postInit(dispatcher, filterConfig);
        } finally {
            if (dispatcher != null) {
                dispatcher.cleanUpAfterInit();
            }
            init.cleanup();
        }
    }
  1. 首先是创建FilterHostConfig类,用于封装filterConfig参数。
    在这个类里就是下get、set方法,该类封装的是filterConfig对象,filterConfiguration是一个接口具体实现类是MockFilterConfig,封装的就是在web.xml配置文件该filter的键值对。
  2. 接着是根据config初始化Struts内部使用的日志。
    在initLogging的方法内部,其实就是传进去一个config对象,然后从该对象中获得一个日志工厂的工厂名,然后根据这个工厂名通过反射的方式创建一个该工厂的实例。
  3. 然后是根据config初始化Dispatcher
//dispatcher的初始化方法
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);
        }
    }
    初始化Dispatcher这一步其实做了很多事情,首先是根据servletContext和filterConfig构造一个Dispatcher对象,然后执行Dispatcher的init()方法,这个方法内部就开始加载Struts的几个配置文件了。

    可以看到这个init()方法的内部就是用来依次加载Struts的几个配置文件,依次是default.properties  、struts-default.xml、struts-plugin.xml、struts.xml,
    其他的一些方法没有仔细深究。

4. 根据servletContext和Dispatcher实例化一个prepareOperation对象和ExecuteOperation对象。
5. 后面的没有细看。

Dofilter()详细步骤:

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;

        try {
            prepare.setEncodingAndLocale(request, response);
            prepare.createActionContext(request, response);
            prepare.assignDispatcherToThread();
            if (excludedPatterns != null && prepare.isUrlExcluded(request, excludedPatterns)) {
                chain.doFilter(request, response);
            } else {
                request = prepare.wrapRequest(request);
                ActionMapping mapping = prepare.findActionMapping(request, response, true);
                if (mapping == null) {
                    boolean handled = execute.executeStaticResourceRequest(request, response);
                    if (!handled) {
                        chain.doFilter(request, response);
                    }
                } else {
                    execute.executeAction(request, response, mapping);
                }
            }
        } finally {
            prepare.cleanupRequest(request);
        }
    }
  1. 在这个方法里首先是处理编码问题和国际化问题,编码方式默认会设置为“ut-8”,区域是使用默认区域。
  2. 创建action容器,这个action容器用来装Request、response、servletContext等,这个方法内部有一个计数器,暂时没看明白这个计数器是用来做什么的,感觉像是用来清理对象但是的,不确定
  3. 关于这个action容器,首先会检查这个容器是否有值,如果有值的话说明应该由一个请求转发,转过来的请求,这是只要将转发前的那个action容器中的值拿过来就好,如果目前容器没有值,那就说明这个请求是一个新的请求,需要重新构建一个action容器供action使用。

  4. 将Dispatcher对象分配给本地线程变量,这一步也不是很懂。

  5. 然后就是执行模式匹配,如果匹配到了就放行。

猜你喜欢

转载自blog.csdn.net/zhaopeng_yu/article/details/72629799