Struts2初始化過程

Struts2運行原理

Struts2基於Servlet框架的filter機制實現。因此須要在web.xml中添加以下配置。java

<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>

當tomcat啓動時,會經過初始化StrutsPrepareAndExecuteFilter加載struts2的相關配置信息。
系統運行時,會攔截request請求,執行struts2的流程。web

request處理流程

  1. 客戶端發送請求apache

  2. 請求先經過StrutsPrepareAndExecuteFilter編程

  3. StrutsPrepareAndExecuteFilter經過ActionMapper來決定這個Request須要調用哪一個Actiontomcat

  4. 若是ActionMapper決定調用某個Action,StrutsPrepareAndExecuteFilter把請求的處理
    交給ActionProxy,這兒已經轉到它的Delegate--Dispatcher來執行多線程

  5. ActionProxy根據ActionMapping和ConfigurationManager找到須要調用的Action類app

  6. ActionProxy建立一個ActionInvocation的實例框架

  7. ActionInvocation調用真正的Action,固然這涉及到相關攔截器的調用ide

  8. Action執行完畢,ActionInvocation建立Result並返回,固然,若是要在返回以前作些什麼,
    能夠實現PreResultListener。添加PreResultListener能夠在Interceptor中實現,不知道其它還有什麼方式?工具

相關概念

ActionMapper

提供Http請求和Action之間的映射,基本上不須要訪問struts的配置文件來肯定request和action的關係。

默認的使用DefaultActionMapper,同時可使用自定義Mapper,可是必需要實現mapper.ActionMapper接口,而且有一個默認的構造器。

ActionMapper會根據request獲取相應的ActionMapping,ActionMapping包含了action的類和方法等詳細信息。

ActionProxy & ActionInvocation

ActionProxy由ActionProxyFactory建立,是Action的代理,用來獲取獲取Action類,也能夠被遠程使用。

ActionProxy會使用ActionInvocation封裝特定request的action,ActionInvocation決定action的動做,執行、攔截、監聽。

簡而言之,ActionProxy封裝request能夠得到的action,ActionInvocation封裝action如何執行。

ConfigurationProvider & Configuration

ConfigurationProvider就是Struts2中配置文件的解析器,Struts2中的配置文件主要是使用StrutsXmlConfigurationProvider來載入xml文件的配置信息。
provider能夠經過DispatcherListener進行配置。

Struts2初始化

Struts2經過初始化StrutsPrepareAndExecuteFilter,加載配置信息。StrutsPrepareAndExecuteFilter的初始化過程以下:

/*
    學習點:1.面向接口編程,耦合度低
           2.適配器模式
 */
 public void init(FilterConfig filterConfig) throws ServletException {
        //封裝了初始化動做的類
        InitOperations init = new InitOperations();
        Dispatcher dispatcher = null;
        try {
            //對filter配置進行封裝,此處有點相似代理模式類型
            FilterHostConfig config = new FilterHostConfig(filterConfig);
            //初始化log
            init.initLogging(config);
            //建立dispatcher對象
            dispatcher = init.initDispatcher(config);
            //初始化靜態資源加載器 
            init.initStaticContentLoader(config, dispatcher);

            //初始化prepare(封裝請求預處理操做)
            prepare = new PrepareOperations(dispatcher);
            //初始化excute (封裝了請求處理操做)
            execute = new ExecuteOperations(dispatcher);
            this.excludedPatterns = init.buildExcludedPatternsList(dispatcher);

            //初始化完成回調方法,默認爲空
            postInit(dispatcher, filterConfig);
        } finally {
            //清理
            if (dispatcher != null) {
                dispatcher.cleanUpAfterInit();
            }
            init.cleanup();
        }
    }

配置信息封裝

傳入FilterConfig接口的實例,而後封裝爲HostConfig的實例FilterHostConfig。在建立的過程當中,調用方法的入參類型大都爲HostConfig類型。

/*
    FilterConfig 爲接口
*/
public class FilterHostConfig implements HostConfig {

    private FilterConfig config;

    public FilterHostConfig(FilterConfig config) {
        this.config = config;
    }
    public String getInitParameter(String key) {
        return config.getInitParameter(key);
    }

    public Iterator<String> getInitParameterNames() {
        return MakeIterator.convert(config.getInitParameterNames());
    }

    public ServletContext getServletContext() {
        return config.getServletContext();
    }
}

logging信息配置

學習:

  1. 利用配置信息很靈活的提供數據,建立LoggerFactory

  2. 命名規範,工廠模式以Factory後綴命名

/**
     * Initializes the internal Struts logging
     */
    public void initLogging( HostConfig filterConfig ) {
        //從配置信息中,讀取loggerFactory配置信息
        String factoryName = filterConfig.getInitParameter("loggerFactory");
        if (factoryName != null) {
            try {
                //利用反射建立LoggerFactory
                Class cls = ClassLoaderUtil.loadClass(factoryName, this.getClass());
                LoggerFactory fac = (LoggerFactory) cls.newInstance();
                LoggerFactory.setLoggerFactory(fac);
            } catch ( InstantiationException e ) {
                System.err.println("Unable to instantiate logger factory: " + factoryName + ", using default");
                e.printStackTrace();
            } catch ( IllegalAccessException e ) {
                System.err.println("Unable to access logger factory: " + factoryName + ", using default");
                e.printStackTrace();
            } catch ( ClassNotFoundException e ) {
                System.err.println("Unable to locate logger factory class: " + factoryName + ", using default");
                e.printStackTrace();
            }
        }
    }

學習:

  1. 在多線程的環境下,建立對象。

public static void setLoggerFactory(LoggerFactory factory) {
        //建立寫鎖
        lock.writeLock().lock();
        try {
            LoggerFactory.factory = factory;
        } finally {
            //在finally內釋放寫鎖
            lock.writeLock().unlock();
        }
    }

在這個過程當中,ClassLoaderUtil是一個載入資源和類的工具,反射類的代碼以下。

學習:

1. 異常的處理形式 
2. 獲取反射的優先級處理
/* @param 類名    The name of the class to load
  * @param 調用方法的類 The Class object of the calling object
  * @throws ClassNotFoundException If the class cannot be found anywhere.
  */
public static Class loadClass(String className, Class callingClass) throws ClassNotFoundException {
        try {
            //從當前線程獲取ClassLoader,而後反射對象
            return Thread.currentThread().getContextClassLoader().loadClass(className);
        } catch (ClassNotFoundException e) {
            try {
                //直接獲取
                return Class.forName(className);
            } catch (ClassNotFoundException ex) {
                try {
                    //從ClassLoaderUtil獲取ClassLoader
                    return ClassLoaderUtil.class.getClassLoader().loadClass(className);
                } catch (ClassNotFoundException exc) {
                    //從callingClass獲取ClassLoader
                    return callingClass.getClassLoader().loadClass(className);
                }
            }
        }
    }

建立dispatcher(分配器)

傳入配置信息(形參爲HostConfig接口,很是靈活!),返回dispatcher。

public Dispatcher initDispatcher( HostConfig filterConfig ) {
        //利用filterConfig信息,建立Dispatcher對象
        Dispatcher dispatcher = createDispatcher(filterConfig);
        dispatcher.init();
        return dispatcher;
    }

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);
        }

        //利用配置信息和ServletContext建立
        return new Dispatcher(filterConfig.getServletContext(), params);
    }

dispatcher的初始化過程比較複雜,不少初始化過程都在其中包含。

public void init() {

        if (configurationManager == null) {
            configurationManager = createConfigurationManager(DefaultBeanSelectionProvider.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);
                }
            }
            errorHandler.init(servletContext);

        } catch (Exception ex) {
            if (LOG.isErrorEnabled())
                LOG.error("Dispatcher initialization failed", ex);
            throw new StrutsException(ex);
        }
    }
相關文章
相關標籤/搜索