struts2源碼學習之初始化(一)

來源:互聯網
上載者:User

標籤:struts2   源碼   源碼分析   struts2初始化   源碼調試   

看struts2源碼已有一段時日,從今天開始,就做一個總結吧。

首先,先看看怎麼調試struts2源碼吧,主要是以下步驟:

使用Myeclipse建立一個web工程

匯入struts2需要的jar包



讓jar包關聯源檔案

在中的jar包右鍵,選擇properties->java source attach,如果關聯成功,雙擊jar包下的某個class檔案就會顯示java原始碼了。

雙擊.class檔案,在原始碼關鍵地方設定斷點

部署工程到Tomcat

Tomcat以Debug方式啟動

經過以上步驟,即可執行單步調試了,這樣就可以很方便的查看代碼的運行狀態了。

struts2架構作為MVC架構,主要作用就是協助處理請求,以一種與web容器無關的方式。也就是說,處理請求時可以不使用HttpServletRequest等類。struts2採用Filter來攔截請求,判斷如果是struts2可以處理的,請求就進入struts2架構進行處理,否則請求進入下一個Filter。

先從Filter的初始化開始來看struts2吧,因為這也是struts2架構初始化的過程。

ok,我們看看struts2的StrutsPrepareAndExecuteFilter類的init()方法:

public void init(FilterConfig filterConfig) throws ServletException {        InitOperations init = new InitOperations();        Dispatcher dispatcher = null;        try {            FilterHostConfig config = new FilterHostConfig(filterConfig);//只是進行了一層薄薄的封裝            init.initLogging(config);//初始化使用者在配置filter時定義的logger            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.封裝init()的參數filterConfig成struts2定義的FilterHostConfig

只是進行了一層薄薄的封裝,代碼如下:

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

2.初始化日誌記錄器,如果使用者在web.xml中配置filter時配置了loggerFactory參數的話

通過InitOperations類的initLogging()。InitOperations類主要是封裝了一些初始化操作,以下是該類的所有方法,從名字也可以看出方法的功能。

public class InitOperations {    public InitOperations()     public void initLogging( HostConfig filterConfig )    public Dispatcher initDispatcher( HostConfig filterConfig )    public StaticContentLoader initStaticContentLoader( HostConfig filterConfig, Dispatcher dispatcher )    public Dispatcher findDispatcherOnThread()    private Dispatcher createDispatcher( HostConfig filterConfig )    public void cleanup()    public List<Pattern> buildExcludedPatternsList( Dispatcher dispatcher )    private List<Pattern> buildExcludedPatternsList( String patterns )}

3.建立Dispatcher並初始化

Dispatcher在struts2中是一個很重要的類,它的工作就是將filter攔截到的請求轉入struts2的請求處理模組。當然,首先Dispatcher會被初始化,它的初始化方法init()可是幹了很多的活呢。這部分在後面會細細的講解,先看看大概是怎樣一個過程吧。在InitOperations類中:

public Dispatcher initDispatcher( HostConfig filterConfig ) {        Dispatcher dispatcher = createDispatcher(filterConfig);        dispatcher.init();        return 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);        }        return new Dispatcher(filterConfig.getServletContext(), params);    }

這裡filter配置的參數會被儲存如Dispatcher對象中,配置如:

<filter>      <filter-name>struts2</filter-name>      <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>      <init-param>      <param-name>filterParam</param-name>  <param-value>abc</param-value>      </init-param>  </filter>

4.初始化靜態資源載入器

public StaticContentLoader initStaticContentLoader( HostConfig filterConfig, Dispatcher dispatcher ) {        StaticContentLoader loader = dispatcher.getContainer().getInstance(StaticContentLoader.class);        loader.setHostConfig(filterConfig);        return loader;    }

在完成了Dispatcher的初始化之後,struts2維護的一個容器Container就建立完成了,可以使用了。這裡通過container建立一個StaticContentLoader對象。

StaticContentLoader是介面,看看該介面聲明了哪些方法:

public interface StaticContentLoader {    public boolean canHandle(String path);    public abstract void setHostConfig(HostConfig filterConfig);    public abstract void findStaticResource(String path, HttpServletRequest request, HttpServletResponse response)            throws IOException;}

struts2有一個實作類別為DefaultStaticContentLoader類。在一般情況下,struts2是不會處理靜態資源的請求的,除非請求的路徑是以struts或static開頭,如有個test應用,那麼請求必須是/test/struts/...或者/test/static/...這樣才會處理。

如果struts2架構不處理靜態資源的請求的話,誰來處理呢?自然是web容器了,比如tomcat。在StrutsPrepareAndExecuteFilter中:

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {<span style="white-space:pre"></span>...                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);                }         ...    }

可以看到,如果不處理,那麼調用chain.doFilter(),請求也就不進入struts2架構了。

那麼,如果要讓struts2架構處理這樣的請求,應該怎麼做呢?

首先,自然是請求的路徑要以struts或static開頭了。

然後,靜態資源應該存放在應用的如下幾個包之一:

struts

org.apache.struts2.static

 template

org.apache.struts2.interceptor.debugging

也可以自己在filter配置參數指定包名:

<init-param>    <param-name>packages</param-name>    <param-value>abc</param-value></init-param>

如果有多個包的話,可以用逗號分隔。

如此即可。

5.建立PrepareOperations對象和ExecuteOperations對象

PrepareOperations和ExecuteOperations有什麼用呢?和InitOperations類似,封裝一些操作。只不過InitOperations是封裝初始化的操作,而前兩者則是封裝請求預先處理和請求處理的操作,當處理請求時方法被調用。先看PrepareOperations有哪些操作:

public class PrepareOperations {    public PrepareOperations(ServletContext servletContext, Dispatcher dispatcher)    public ActionContext createActionContext(HttpServletRequest request, HttpServletResponse response)    public void cleanupRequest(HttpServletRequest request)    public void assignDispatcherToThread()     public void setEncodingAndLocale(HttpServletRequest request, HttpServletResponse response)    public HttpServletRequest wrapRequest(HttpServletRequest oldRequest)     public ActionMapping findActionMapping    (HttpServletRequest request, HttpServletResponse response)    public ActionMapping findActionMapping(HttpServletRequest request, HttpServletResponse response, boolean forceLookup)    public void cleanupDispatcher()    public boolean isUrlExcluded( HttpServletRequest request, List<Pattern> excludedPatterns )     private String getUri( HttpServletRequest request )}

ExecuteOperations就簡單得多了:

public class ExecuteOperations {    private ServletContext servletContext;    private Dispatcher dispatcher;    public ExecuteOperations(ServletContext servletContext, Dispatcher dispatcher) {        this.dispatcher = dispatcher;        this.servletContext = servletContext;    }    /**     * Tries to execute a request for a static resource     * @return True if it was handled, false if the filter should fall through     * @throws IOException     * @throws ServletException     */    public boolean executeStaticResourceRequest(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {        // there is no action in this request, should we look for a static resource?        String resourcePath = RequestUtils.getServletPath(request);        if ("".equals(resourcePath) && null != request.getPathInfo()) {            resourcePath = request.getPathInfo();        }        StaticContentLoader staticResourceLoader = dispatcher.getContainer().getInstance(StaticContentLoader.class);        if (staticResourceLoader.canHandle(resourcePath)) {            staticResourceLoader.findStaticResource(resourcePath, request, response);            // The framework did its job here            return true;        } else {            // this is a normal request, let it pass through            return false;        }    }    /**     * Executes an action     * @throws ServletException     */    public void executeAction(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping) throws ServletException {        dispatcher.serviceAction(request, response, servletContext, mapping);    }}

關於請求的處理,後面詳細講。這裡就當做是一個熱身吧。

6.封裝配置filter時指定的不處理的action請求的pattern成List<Pattern>

這個配置是通過STRUTS_ACTION_EXCLUDE_PATTERN這個常量設定的。在struts.xml或者struts.properties檔案中配置。

7.完成一些清理工作

其實也沒清理多少東西了。


ok,初始化的基本流程分析完了,但其中Dispatcher的初始化還是一個黑盒。所以下一篇就詳細分析Dispatcher的初始化。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.