Tomcat8源碼分析-啓動流程-MapperListener啓動

上一篇:Tomcat8源碼分析-啓動流程-start方法java

MapperListener啓動主要完成了將資源(class目錄、jar、servlet-mapping、welcome list)添加MappedHost下的ContextVersion的不一樣Wrappers數組當中,以及將本身設置爲該Engine及其下面是全部容器的ContainerListener與LifeCycleListener設計模式

完成上面的功能有什麼做用喃???能夠說過重要了,看到「servlet-mapping」就應該想到確定是與處理請求的時候相關的,沒錯,當Tomcat處理請求的時候就會根據path與上面處理造成的Wrappers數組進行匹配獲得Servlet,並設置給StandardWrapperValve.StandardWrapper.servlet,最終才能調用到對應Servlet的方法。數組

看看源碼app

StandardService部分jsp

protected void startInternal() throws LifecycleException {

        。。。。。省略其餘代碼。。。。。

        /** 很重要
         * 會完成以下資源的解析與加載
         * 1.將Context下的Wrapper(自定義的Servlet\defaultServlet\jspServlet\jspxServlet)進行分析,並最終拆分爲ContextVersion的四個Wrapper數組,
         *   exactWrappers\wildcardWrappers\extensionWrappers\defaultWrapper,他們在Tomcat接收請求時被用做與path匹配,最終得
         *   到想要的Servlet
         * 2.將Context中的WebResource(裏面包含了好比class目錄、jar包添加到ContextVersion
         * 3.將welcome list配置添加到ContextVersion
         *
         */

        mapperListener.start();

        。。。。。省略其餘代碼。。。。。
    }

調用start方法(按照前面講的模板方法設計模式套路),緊接着會按照Mapper.registerHost-Mapper.registerContext-Mapper.addContextVersion-Mapper.addWrappers-Mapper.-Mapper.addWrapper這個順序進入到下面的源代碼,在這裏面就完成了默認Servlet和自定義Sevlet的Mapping規則加載,等候被使用。源碼分析

protected void addWrapper(ContextVersion context, String path,
            Wrapper wrapper, boolean jspWildCard, boolean resourceOnly) {

        synchronized (context) {
            if (path.endsWith("/*")) {//以"/*"開始的path加入到通配符wrapper當中
                // Wildcard wrapper
                String name = path.substring(0, path.length() - 2);
                MappedWrapper newWrapper = new MappedWrapper(name, wrapper,
                        jspWildCard, resourceOnly);
                MappedWrapper[] oldWrappers = context.wildcardWrappers;
                MappedWrapper[] newWrappers = new MappedWrapper[oldWrappers.length + 1];
                if (insertMap(oldWrappers, newWrappers, newWrapper)) {
                    context.wildcardWrappers = newWrappers;
                    int slashCount = slashCount(newWrapper.name);
                    if (slashCount > context.nesting) {
                        context.nesting = slashCount;
                    }
                }
            } else if (path.startsWith("*.")) {//以"*."開始的path加入到後綴Wrapper當中
                // Extension wrapper
                String name = path.substring(2);
                MappedWrapper newWrapper = new MappedWrapper(name, wrapper,
                        jspWildCard, resourceOnly);
                MappedWrapper[] oldWrappers = context.extensionWrappers;
                MappedWrapper[] newWrappers =
                    new MappedWrapper[oldWrappers.length + 1];
                if (insertMap(oldWrappers, newWrappers, newWrapper)) {
                    context.extensionWrappers = newWrappers;
                }
            } else if (path.equals("/")) {//設置默認的DefaultMapper
                // Default wrapper
                MappedWrapper newWrapper = new MappedWrapper("", wrapper,
                        jspWildCard, resourceOnly);
                context.defaultWrapper = newWrapper;
            } else { //到這裏都還沒匹配到的就是精確Wrapper了
                // Exact wrapper
                final String name;
                if (path.length() == 0) {
                    // Special case for the Context Root mapping which is
                    // treated as an exact match
                    name = "/";
                } else {
                    name = path;
                }
                MappedWrapper newWrapper = new MappedWrapper(name, wrapper,
                        jspWildCard, resourceOnly);
                MappedWrapper[] oldWrappers = context.exactWrappers;
                MappedWrapper[] newWrappers = new MappedWrapper[oldWrappers.length + 1];
                if (insertMap(oldWrappers, newWrappers, newWrapper)) {
                    context.exactWrappers = newWrappers;
                }
            }
        }
    }

再來看看ContextVersion實例化的時候傳的參數有哪些,這些參數就說明了它包含了那些資源.net

//將新生成的Context添加到Host的contextList當中。在這裏也驗證了一個Host能夠有多個Context(一個應用)
        mapper.addContextVersion(host.getName(), host, contextPath,
                context.getWebappVersion(), context, welcomeFiles, resources,
                wrappers);

其中的resources就是WebResource,裏面就是以前已經解析完成的目錄與jar資源設計

 

再來看看ContextVersion在Debug時構造完成後幾個關鍵屬性中的值code

這張圖看清楚了Tomcat啓動以後有哪些Wrapper(也就是Servlet能夠使用)blog

這張圖再點進去看能夠看到目錄與jar相關信息

 

總結

MapperListener真的很重要,完成了很是核心的servlet-mapping的分析與加載,讓處理請求的階段能夠找到對照表(4中Wrappers數組)進行匹配,從而可以正確的進行業務邏輯處理。

相關文章
相關標籤/搜索