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
客戶端發送請求apache
請求先經過StrutsPrepareAndExecuteFilter編程
StrutsPrepareAndExecuteFilter經過ActionMapper來決定這個Request須要調用哪一個Actiontomcat
若是ActionMapper決定調用某個Action,StrutsPrepareAndExecuteFilter把請求的處理
交給ActionProxy,這兒已經轉到它的Delegate--Dispatcher來執行多線程
ActionProxy根據ActionMapping和ConfigurationManager找到須要調用的Action類app
ActionProxy建立一個ActionInvocation的實例框架
ActionInvocation調用真正的Action,固然這涉及到相關攔截器的調用ide
Action執行完畢,ActionInvocation建立Result並返回,固然,若是要在返回以前作些什麼,
能夠實現PreResultListener。添加PreResultListener能夠在Interceptor中實現,不知道其它還有什麼方式?工具
提供Http請求和Action之間的映射,基本上不須要訪問struts的配置文件來肯定request和action的關係。
默認的使用DefaultActionMapper,同時可使用自定義Mapper,可是必需要實現mapper.ActionMapper
接口,而且有一個默認的構造器。
ActionMapper會根據request獲取相應的ActionMapping,ActionMapping包含了action的類和方法等詳細信息。
ActionProxy由ActionProxyFactory建立,是Action的代理,用來獲取獲取Action類,也能夠被遠程使用。
ActionProxy會使用ActionInvocation封裝特定request的action,ActionInvocation決定action的動做,執行、攔截、監聽。
簡而言之,ActionProxy封裝request能夠得到的action,ActionInvocation封裝action如何執行。
ConfigurationProvider就是Struts2中配置文件的解析器,Struts2中的配置文件主要是使用StrutsXmlConfigurationProvider來載入xml文件的配置信息。
provider能夠經過DispatcherListener進行配置。
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(); } }
學習:
利用配置信息很靈活的提供數據,建立LoggerFactory
命名規範,工廠模式以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(); } } }
學習:
在多線程的環境下,建立對象。
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); } } } }
傳入配置信息(形參爲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); } }