请求处理-struts2源码解析

struts2架框处理流程图

请求处理-struts2源码解析

一、Struts2架框处理流程概序

        请求首先通过Filter chain,Filter主要包括ActionContextCleanUp,它主要清理当前线程的ActionContext和 Dispatcher;FilterDispatcher主要通过AcionMapper来决定需要调用哪个Action。

        ActionMapper取得了ActionMapping后,在Dispatcher的serviceAction方法里创建 ActionProxy,ActionProxy创建ActionInvocation,然后ActionInvocation调用 Interceptors,执行Action本身,创建Result并返回,当然,如果要在返回之前做些什么,可以实现 PreResultListener。
二、Struts2部分类介绍 (这部分从Struts2参考文档中翻译而来。)
1、ActionMapper
        ActionMapper其实是HttpServletRequest和Action调用请求的一个映射,它屏蔽了Action对于Request等 java Servlet类的依赖。Struts2中它的默认实现类是DefaultActionMapper,ActionMapper很大的用处可以根据自己的需要来设计url格式,它自己也有Restful的实现,具体可以参考文档的docs\actionmapper.html。
2、ActionProxy&ActionInvocation
        Action的一个代理,由ActionProxyFactory创建,它本身不包括Action实例,默认实现DefaultActionProxy 是由ActionInvocation持有Action实例。ActionProxy作用是如何取得Action,无论是本地还是远程。而 ActionInvocation的作用是如何执行Action,拦截器的功能就是在ActionInvocation中实现的。
3、ConfigurationProvider&Configuration
        ConfigurationProvider就是Struts2中配置文件的解析器,Struts2中的配置文件主要是尤其实现类 XmlConfigurationProvider及其子类StrutsXmlConfigurationProvider来解析。
三、Struts2请求流程
1、客户端发送请求
2、请求先通过ActionContextCleanUp-->FilterDispatcher
3、FilterDispatcher通过ActionMapper来决定这个Request需要调用哪个Action
4、如果ActionMapper决定调用某个Action,FilterDispatcher把请求的处理交给ActionProxy,这儿已经转到它的Delegate--Dispatcher来执行
5、ActionProxy根据ActionMapping和ConfigurationManager找到需要调用的Action类
6、ActionProxy创建一个ActionInvocation的实例
7、ActionInvocation调用真正的Action,当然这涉及到相关拦截器的调用
8、Action执行完毕,ActionInvocation创建Result并返回,当然,如果要在返回之前做些什么,可以实现PreResultListener。添加PreResultListener可以在Interceptor中实现,不知道其它还有什么方式?
四、Struts2(2.1.2)部分源码阅读
    从org.apache.struts2.dispatcher.FilterDispatcher开始
/**
     * Initializes the filter by creating a default dispatcher
     * and setting the default packages for static resources.
     *
     * @param filterConfig The filter configuration
     */
    public void init(FilterConfig filterConfig) throws ServletException {
        try {
            this.filterConfig = filterConfig;
            //初始化日志工厂
            initLogging();
            //将Filter的配置中的所有属性都写入一个HashMap,并作为参数传递给Dispatcher的构造函数。 
            dispatcher = createDispatcher(filterConfig);

            dispatcher.init();
            dispatcher.getContainer().inject(this);

            staticResourceLoader.setHostConfig(new FilterHostConfig(filterConfig));
        } finally {
            ActionContext.setContext(null);
        }
    }
 
   //读取配置文件中的信息保存至HashMap中
/**
     * Create a default {@link Dispatcher} that subclasses can override
     * with a custom Dispatcher, if needed.
     *
     * @param filterConfig Our FilterConfig
     * @return Initialized Dispatcher
     */
    protected Dispatcher createDispatcher(FilterConfig filterConfig) {
        Map<String, String> params = new HashMap<String, String>();
        for (Enumeration e = filterConfig.getInitParameterNames(); e.hasMoreElements();) {
            String name = (String) e.nextElement();
            String value = filterConfig.getInitParameter(name);
            params.put(name, value);
        }
        return createDispatcher(filterConfig.getServletContext(), params);
    }
   
   //创建一个Dispatcher(org.apache.struts2.dispatcher   Dispatcher 类
/**
     * Create a default {@link Dispatcher} that subclasses can override
     * with a custom Dispatcher, if needed.  Called by
     * createDispatcher(FilterConfig).
     *
     * @param ctx ServletContext
     * @param params parameters from FilterConfig
     * @return Initialized Dispatcher
     */
    protected Dispatcher createDispatcher(ServletContext ctx, Map<String, String> params) {
        return new Dispatcher(ctx, params);
    }
 
   // Dispatcher类 init方法
/**
     * Load configurations, including both XML and zero-configuration strategies,
     * and update optional settings, including whether to reload configurations and resource files.
     */
    public void init() {

    	if (configurationManager == null) {
    		configurationManager = createConfigurationManager(BeanSelectionProvider.DEFAULT_BEAN_NAME);
    	}

        try {
            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_CheckConfigurationReloading(container);
            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);
        }
    }
 
   [1]、主要读取struts 默认配置default.properties文件中的参数(如:编码、后缀等一些基础配置参数)
private void init_DefaultProperties() {
        configurationManager.addConfigurationProvider(new DefaultPropertiesProvider());
    }
 
[2]、这个方法主要是用于载入FilterDispatcher定义的config
如果读取初始化的HashMap列表中没有config这个属性,则struts会默认载入:
struts-default.xml,struts-plugin.xml,struts.xml 这三个文件,并且判断是否有xwork.xml,如果有则载入xwork的DTD,否则载入struts的DTD。
 
private void init_TraditionalXmlConfigurations() {
        String configPaths = initParams.get("config"); 
        if (configPaths == null) {
            configPaths = DEFAULT_CONFIGURATION_PATHS;  
        }
        String[] files = configPaths.split("\\s*[,]\\s*");
        for (String file : files) {
            if (file.endsWith(".xml")) {
                if ("xwork.xml".equals(file)) {
                    configurationManager.addContainerProvider(createXmlConfigurationProvider(file, false));
                } else {
                    configurationManager.addContainerProvider(createStrutsXmlConfigurationProvider(file, false, servletContext));
                }
            } else {
                throw new IllegalArgumentException("Invalid configuration file name");
            }
        }
    }

[3]、好像是初始化架框编码

private void init_LegacyStrutsProperties() {
        configurationManager.addContainerProvider(new LegacyPropertiesConfigurationProvider());
    }

相关推荐