章節簡言 |
上一章筆者試着建一個Hello world的例子。是一個空白的struts2例子。明白了運行struts2至少須要用到哪一些Jar包。而這一章筆者將根據前面章節(Struts2 源碼分析——核心機制)裏的機制圖片來分析源碼。若是還不明白核心機制的朋友,請轉到對應的章節進行閱讀。筆者爲了方便讀者閱讀,也把圖片在次貼到了本章中。以下html
根據圖片筆者就明白咱們首要分析即是橙黃色(Servlet Filters)。也就是傳說的過濾器(Filter)。相信看過筆者前面幾個章節的讀者都明白struts2的配置方式有二種。便是StrutsPrepareFilter+StrutsExecuteFilter和StrutsPrepareAndExecuteFilter。不論是哪種大部分都是同樣子。筆者用的是StrutsPrepareFilter+StrutsExecuteFilter來分析。那麼讓咱們看看關於他們到底作了些什麼。Prepare意爲「準備」。猜的沒有錯。StrutsPrepareFilter類就是爲了開啓struts2以前加載一個相關的配置和執行的必要信息。同理,Execute意爲「運行」。咱們也就能夠想像StrutsExecuteFilter類就是執行struts2。所謂分析就是要有一種勇於想像和猜想的心態。而後在證實就好了。java
另外這裏有聲明一下:筆者這裏只想講一些有關struts2相關的知識。而像SiteMesh之類的筆者並不會深刻。正則表達式
StrutsPrepareFilter類的工做 |
StrutsPrepareFilter這個類必須在StrutsExecuteFilter類以前運行。不然就會出錯。固然struts2運行起來的時候,框架也有相關的提示你。那麼先讓咱們看一下代碼吧。以下apache
1 package org.apache.struts2.dispatcher.filter; 2 3 import org.apache.struts2.StrutsStatics; 4 import org.apache.struts2.dispatcher.Dispatcher; 5 import org.apache.struts2.dispatcher.InitOperations; 6 import org.apache.struts2.dispatcher.PrepareOperations; 7 8 import javax.servlet.Filter; 9 import javax.servlet.FilterChain; 10 import javax.servlet.FilterConfig; 11 import javax.servlet.ServletException; 12 import javax.servlet.ServletRequest; 13 import javax.servlet.ServletResponse; 14 import javax.servlet.http.HttpServletRequest; 15 import javax.servlet.http.HttpServletResponse; 16 import java.io.IOException; 17 import java.util.List; 18 import java.util.regex.Pattern; 19 20 public class StrutsPrepareFilter implements StrutsStatics, Filter { 21 22 protected static final String REQUEST_EXCLUDED_FROM_ACTION_MAPPING = StrutsPrepareFilter.class.getName() + ".REQUEST_EXCLUDED_FROM_ACTION_MAPPING"; 23 24 protected PrepareOperations prepare;//用於每一次請求以前,執行一些功能的類。 25 protected List<Pattern> excludedPatterns = null; 26 27 public void init(FilterConfig filterConfig) throws ServletException { 28 InitOperations init = new InitOperations();//用於初始化相關的功能操做。你能夠理解爲工具類同樣子。 29 Dispatcher dispatcher = null;//這個類至關的重要。他的做用鏈接着StrutsExecuteFilter。這裏能夠命名爲調結者。 30 try { 31 FilterHostConfig config = new FilterHostConfig(filterConfig);//這裏能夠理解爲把filterConfig在進行封裝FilterHostConfig更爲主便操做和理解。 32 init.initLogging(config);//獲取名爲loggerFactory的參數,並實例化這個類。通常爲去用戶自定義日誌。 33 dispatcher = init.initDispatcher(config);//初化調結者。這裏是重要。 34 35 prepare = new PrepareOperations(dispatcher); 36 this.excludedPatterns = init.buildExcludedPatternsList(dispatcher);//加載排除在內的action的正則表達式 37 38 postInit(dispatcher, filterConfig); 39 } finally { 40 if (dispatcher != null) { 41 dispatcher.cleanUpAfterInit(); 42 } 43 init.cleanup(); 44 } 45 } 46 47 protected void postInit(Dispatcher dispatcher, FilterConfig filterConfig) { 48 } 49 50 public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { 51 52 HttpServletRequest request = (HttpServletRequest) req; 53 HttpServletResponse response = (HttpServletResponse) res; 54 55 try { 56 if (excludedPatterns != null && prepare.isUrlExcluded(request, excludedPatterns)) { 57 request.setAttribute(REQUEST_EXCLUDED_FROM_ACTION_MAPPING, new Object()); 58 } else { 59 prepare.setEncodingAndLocale(request, response);//設置請求的格式編碼。 60 prepare.createActionContext(request, response);//action的上下文 61 prepare.assignDispatcherToThread();//把Dispatcher放入本地線程裏面。 62 request = prepare.wrapRequest(request); 63 prepare.findActionMapping(request, response);//找到action映射的信息 64 } 65 chain.doFilter(request, response); 66 } finally { 67 prepare.cleanupRequest(request); 68 } 69 } 70 71 public void destroy() { 72 prepare.cleanupDispatcher(); 73 } 74 75 }
上面的源碼也作了一些簡單的註解。固然這是筆者的理解。若是你看了源碼以爲筆者理解的不對。沒事!只要讀者本身內心面明白原理的話就能夠了。咱們能夠看到了好多的類,對於筆者來說之前有過經驗,看起來比較輕鬆。可是對於四年前初學者的我來說,那真是天書。筆者一個一個解釋給讀者聽也不現實。這裏筆者只把主要的相關類拿出來說解。但願讀者們見諒!StrutsPrepareFilter類現實於接口StrutsStatics。這接口都是大量常量。而StrutsPrepareFilter類自己有二個成員變量。其中一個成員變量prepare(PrepareOperations類)的工做以下。session
prepare成員變量的工做:app
1.設置request請求的本地化。便是:本地語言和編碼格式。框架
2.建立一個新的action上下文。對於上下文不理解的讀者能夠查看相關的文章。若是不行的話,筆者認爲你能夠理解爲進入房間的門同樣子。action請求則是房間。新建一個房間就有一個新的門。新action請求就有一個新的action上下文。ide
3.把當前的Dispatcher實例存放到當前的本地線程(ThreadLocal)中。而Dispatcher類是一個重要的核心類,struts2的action請求就是靠他來執行的。(對於Dispatcher類的做用不理解的話。沒有事。後面我會對Dispatcher進行講解)工具
4.把HttpServletRequest請求封裝成爲StrutsRequestWrapper或是MultiPartRequestWrapper。能夠說這部分的工做也是靠Dispatcher實例來執行的。源碼分析
5.找到action映射類(ActionMapping)的實例。並把他存在到request請求裏面。他對應的Key爲「struts.actionMapping」; 讀者會問ActionMapping類是什麼東東。如今能夠理解爲裏面存放用戶action的配置信息。大白話就是用戶在地址欄上輸入URL找到對應的action類。
以上是prepare成員變量的工做,他是主要目的就是根據request請求找到對應action映射。以便於StrutsExecuteFilter類根據action映射類裏面的信息找到對應的用戶action類,並執行。從這裏筆者就能夠明顯感受出來,StrutsPrepareFilter類是執行action請求以前的相關準備工做。那麼敏感的讀者就會問:「正常在這以前應該會加載或初始化相關的配置信息纔對啊?否則他後面執行action請求什麼工做呢?」。沒有錯。讓咱們看一下過濾器(Filter)的方法init吧。能夠明確的指出加載相關的配置信息就在這裏進行的。他的工做以下
init方法:
1.查看用戶是否有自定義日誌類。若是有,初始化並實例用戶定義的日誌類。存放到LoggerFactory類裏面。LoggerFactory類裏面用的是單例模式。
2.實例化Dispatcher類,並初始化加載相關的配置的信息文件。如 default.properties文件,struts-default.xml文件等等。
3.實例化PrepareOperations類,Dispatcher實例存放進去。爲以後的request請求工做作準備。便是上面PrepareOperations類所講的。
4.加載用戶自定義不該該被外部訪問的action相對應的正則表達式。這邊也就是StrutsPrepareFilter類裏面的另外一個成員變量。
正如上述所講的就是StrutsPrepareFilter類的工做。簡單點講就是爲action請求執行以前作好一切準備的類。其中init方法就是用於加載相關配置文件,初始化信息的工做。而PrepareOperations類是用於request請求的處理。其中包設置格式,找對應的action映射類等等操做。便是ActionMapping類。
StrutsExecuteFilter類的工做 |
上面講到StrutsPrepareFilter類的工做,那麼對於StrutsExecuteFilter類的工做就顯得很簡單。就是執行action請求。讓咱們先看一下代碼吧。以下
1 package org.apache.struts2.dispatcher.filter; 2 3 import org.apache.struts2.StrutsStatics; 4 import org.apache.struts2.dispatcher.Dispatcher; 5 import org.apache.struts2.dispatcher.mapper.ActionMapping; 6 import org.apache.struts2.dispatcher.ExecuteOperations; 7 import org.apache.struts2.dispatcher.InitOperations; 8 import org.apache.struts2.dispatcher.PrepareOperations; 9 10 import javax.servlet.*; 11 import javax.servlet.http.HttpServletRequest; 12 import javax.servlet.http.HttpServletResponse; 13 import java.io.IOException; 14 15 public class StrutsExecuteFilter implements StrutsStatics, Filter { 16 protected PrepareOperations prepare;//用於每一次請求以前,執行一些功能的類。 17 protected ExecuteOperations execute;//用於執行請求的功能類。 18 19 protected FilterConfig filterConfig; 20 21 public void init(FilterConfig filterConfig) throws ServletException { 22 this.filterConfig = filterConfig; 23 } 24 25 protected synchronized void lazyInit() { 26 if (execute == null) { 27 InitOperations init = new InitOperations();//用於初始化的功能類 28 Dispatcher dispatcher = init.findDispatcherOnThread(); 29 init.initStaticContentLoader(new FilterHostConfig(filterConfig), dispatcher); 30 31 prepare = new PrepareOperations(dispatcher); 32 execute = new ExecuteOperations(dispatcher); 33 } 34 35 } 36 37 public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { 38 39 HttpServletRequest request = (HttpServletRequest) req; 40 HttpServletResponse response = (HttpServletResponse) res; 41 42 if (excludeUrl(request)) {//用於判斷是否在排除的action以內。若是是就跳過。 43 chain.doFilter(request, response); 44 return; 45 } 46 47 if (execute == null) { 48 lazyInit();//初始化相關的信息類。 49 } 50 51 ActionMapping mapping = prepare.findActionMapping(request, response);//找到ActionMapping實例 52 53 54 Integer recursionCounter = (Integer) request.getAttribute(PrepareOperations.CLEANUP_RECURSION_COUNTER); 55 56 if (mapping == null || recursionCounter > 1) { 57 boolean handled = execute.executeStaticResourceRequest(request, response); 58 if (!handled) { 59 chain.doFilter(request, response); 60 } 61 } else { 62 execute.executeAction(request, response, mapping);//執行action請求 63 } 64 } 65 66 private boolean excludeUrl(HttpServletRequest request) { 67 return request.getAttribute(StrutsPrepareFilter.REQUEST_EXCLUDED_FROM_ACTION_MAPPING) != null; 68 } 69 70 public void destroy() { 71 prepare = null; 72 execute = null; 73 filterConfig = null; 74 } 75 76 }
筆者在這個類上的註解比較簡單,主要是筆者不知道這個類什麼樣子去講。由於這個類比StrutsPrepareFilter類來說簡單多了。工做也很單一。因此筆者一會兒不知道要什麼樣子去註解。筆者認爲這個類的重點有二個地方。一是lazyInit方法,二是ExecuteOperations類的工做。而其中lazyInit方法主要是用於初始化相關須要的類。並無值得注意的點。那麼爲何筆者卻要說他是重點之一呢?問題在於他還有一個工做是初始化靜態內容加載器(StaticContentLoader類)。惋惜不是本章的重點。因此筆者要講的是ExecuteOperations類的工做。以下
ExecuteOperations類的工做:
1.組裝相關的Map類。如requestMap,params,session 等。
2.找到ActionProxy類。該類是用於執行action請求的。也是關鍵的類。(後面章節會講到)
3.組裝action請求執行的結果。也是關鍵的類。(後面章節會講到)
StrutsExecuteFilter類的工做目前只須要知道他是執行action請求的。若是讀者不明白不要擔憂。筆者後面會講到。
本章總結 |
本章的重點並非要知道如何去執行action請求。而是知道在執行action請求以前要作些什麼工做。只要明白了這一點咱們就知道目標是什麼。因此在本章筆者在講StrutsPrepareFilter類的時候,講的比較多。就是要讓讀者明白準備工做都有哪些什麼。