亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

死磕Tomcat7源碼之一:解析web.xml

發布時間:2020-07-01 09:12:00 來源:網絡 閱讀:6448 作者:randy_shandong 欄目:開發技術

熟悉java web開發的同學都清楚,tomcat作為一款非常流行的servlet容器,開源,流行,配置簡單,不需要贅述。個人認為,web.xml作為webapp的入口,弄清楚該文件的底層解析過程,進而可以窺探tomcat的底層工作機制,搞明白tomcat對servlert規范的實現機理。

通過本文,可以知道以下部分內容

  • webapp部署3種部署方式

  • webapp web.xml解析流程

  • webapp Context對象信息的生成(不包括對象的生成)

總體來說,webapp部署有三種方式:XML文件描述符、WAR包、文件目錄。三種方式部署的總體流程很相似,都是一個web應用分配一個線程來處理,這里統一放到與Host內部的線程池對象中(startStopExecutor),所以有時會看到在默認配置下Tomcat啟動后可能有一個叫“-startStop-”的線程還會運行一段時間才結束。但瀏覽這三種部署方式的實現代碼,里面都是構建一個Context對象,并將構建好的Context對象與Host組件關聯起來


1.三種部署方式

    /**
     * 部署應用,該方法被org.apache.catalina.startup.HostConfig.start()調用
     * 包含3種部署方式,每個部署方式分別使用內部類,分配一個線程處理
     */
    protected void deployApps() {

        File appBase = appBase();
        File configBase = configBase();
        String[] filteredAppPaths = filterAppPaths(appBase.list());
        // Deploy XML descriptors from configBase
        deployDescriptors(configBase, configBase.list());
        // Deploy WARs
        deployWARs(appBase, filteredAppPaths);
        // Deploy expanded folders
        deployDirectories(appBase, filteredAppPaths);

    }

3個部署的內部類

org.apache.catalina.startup.HostConfig.DeployWar
org.apache.catalina.startup.HostConfig.DeployDescriptor

org.apache.catalina.startup.HostConfig.DeployDirectory

2.從部署webapp到解析web.xml序列圖

死磕Tomcat7源碼之一:解析web.xml

找了很多網上資料,對從部署webapp開始,到開始解析web.xml這一段處理過程,沒找到相關資料。個人就花時間整理出這個序列圖,填補下這方面的空缺。通過該圖,可以很清楚的知道,這部分主要完成了2件事:

(1)啟動StandardContext,并將context對象添加到StandardHost對象中。

(2)通過觸發事件機制,開始Context的解析過程。

3.web.xml解析過程

接第二步驟中序列圖,開始分析web.xml的解析過程。從ContextConfig開始。

3.1 org.apache.catalina.startup.ContextConfig.configureStart()

   /**
     * Process a "contextConfig" event for this Context.
     */
    protected synchronized void configureStart() {
        // Called from StandardContext.start()

        webConfig();

        if (ok) {
            validateSecurityRoles();
        }
        // Configure an authenticator if we need one
        if (ok)
            authenticatorConfig();
        // Make our application available if no problems were encountered
        if (ok)
            context.setConfigured(true);
        else {
            log.error(sm.getString("contextConfig.unavailable"));
            context.setConfigured(false);
        }
    }

該方法通過調用webConfig(),具體完成解析工作,此外完成了安全驗證相關內容。

3.2 org.apache.catalina.startup.ContextConfig.webConfig()方法

   /**
     * Scan the web.xml files that apply to the web application and merge them
     * using the rules defined in the spec. For the global web.xml files,
     * where there is duplicate configuration, the most specific level wins. ie
     * an application's web.xml takes precedence over the host level or global
     * web.xml file.
     */
    protected void webConfig() {
       
        Set<WebXml> defaults = new HashSet<WebXml>();
        defaults.add(getDefaultWebXmlFragment());
        WebXml webXml = createWebXml();

        // Parse context level web.xml
        InputSource contextWebXml = getContextWebXmlSource();
        parseWebXml(contextWebXml, webXml, false);//解析

        ServletContext sContext = context.getServletContext();

        // Ordering is important here
        // Step 1. Identify all the JARs packaged with the application
        // If the JARs have a web-fragment.xml it will be parsed at this
        // point.
        Map<String,WebXml> fragments = processJarsForWebFragments(webXml);

        // Step 2. Order the fragments.
        Set<WebXml> orderedFragments = null;
        orderedFragments =
                WebXml.orderWebFragments(webXml, fragments, sContext);

        // Step 3. Look for ServletContainerInitializer implementations
        if (ok) {
            processServletContainerInitializers();
        }


            // Step 5. Process JARs for annotations - only need to process
            // those fragments we are going to use
            if (ok) {
                processAnnotations(
                        orderedFragments, webXml.isMetadataComplete());
            }

            // Cache, if used, is no longer required so clear it
            javaClassCache.clear();
        }
                    // Step 6. Merge web-fragment.xml files into the main web.xml
                    // Step 7. Apply global defaults
              webXml.merge(defaults);
               // Step 8. Convert explicitly mentioned jsps to servlets
                    convertJsps(webXml);
                     // Step 9. Apply merged web.xml to Context
                    webXml.configureContext(context);

        // Step 9a. Make the merged web.xml available to other
        // components, 

        // Always need to look for static resources
        // Step 10. Look for static resources packaged in JARs
                proce***esourceJARs(resourceJars);
                // See also StandardContext.resourcesStart() for
                // WEB-INF/classes/META-INF/resources configuration

        // Step 11. Apply the ServletContainerInitializer config to the
        // context
                    context.addServletContainerInitializer(
                            entry.getKey(), entry.getValue());
    }

通過源碼中的注釋,step1 到step11。主要工作包含:1.解析xml,2.合并xml,3.組裝Context,4.編譯JSP。具體步驟,參考說明

  1. 掃描應用打包的所有Jar來檢索Jar包里面的web.xml配置并解析,放入內存。

  2. 對這些已經檢索到的web配置進行排序。

  3. 基于SPI機制查找ServletContainerInitializer的實現,寫web中間件的同學注意了,了解SPI以及                           ServletContainerInitializer機制這對于你來說可能是一個很好的知識點。

  4. 處理/WEB-INF/classes下面的類的注解,某個版本Servlet支持注解方式的配置,可以猜測相關事宜就是在這里干的。

  5. 處理Jar包中的注解類。

  6. 將web配置按照一定規則合并到一起。

  7. 應用全局默認配置,還記得Tomcat包下面的conf文件夾下面有個web.xml配置文件吧。

  8. 將JSP轉換為Servlet,這讓我想起了若干年前對JSP的理解。

  9. 將web配置應用到Servlet上下文,也即Servlet容器。

  10. 將配置信息保存起來以供其他組件訪問,使得其他組件不需要再次重復上面的步驟去獲取配置信息了。

  11. 檢索Jar包中的靜態資源。

  12. 將ServletContainerInitializer配置到上下文。

3.3 org.apache.catalina.startup.ContextConfig.parseWebXml方法

    /**
     * Parses the given source and stores the parsed data in the given web.xml
     * representation. The byte stream will be closed at the end of the parse
     * operation.
     *
     * @param source Input source containing the XML data to be parsed
     * @param dest The object representation of common elements of web.xml and
     *             web-fragment.xml
     * @param fragment Specifies whether the source is web-fragment.xml or
     *                 web.xml
     */
    protected void parseWebXml(InputSource source, WebXml dest,
            boolean fragment) {
        XmlErrorHandler handler = new XmlErrorHandler();

        Digester digester;
        WebRuleSet ruleSet;
        if (fragment) {
            digester = webFragmentDigester;
            ruleSet = webFragmentRuleSet;
        } else {
            digester = webDigester;
            ruleSet = webRuleSet;
        }

        digester.push(dest);
        digester.setErrorHandler(handler);

        digester.parse(source);
       }

使用Digester 對象即系web.xml,并將結果保存到WebXml對象中。

3.4 Digester的解析規則

(1)構造Digester.createWebXmlDigester

    public void createWebXmlDigester(boolean namespaceAware,
            boolean validation) {

        boolean blockExternal = context.getXmlBlockExternal();
        
        webRuleSet = new WebRuleSet(false);
        webDigester = DigesterFactory.newDigester(validation,
                namespaceAware, webRuleSet, blockExternal);
        webDigester.getParser();

        webFragmentRuleSet = new WebRuleSet(true);
        webFragmentDigester = DigesterFactory.newDigester(validation,
                namespaceAware, webFragmentRuleSet, blockExternal);
        webFragmentDigester.getParser();
    }

(2)配置解析規則 WebRuleSet.addRuleInstances

  /**
     * <p>Add the set of Rule instances defined in this RuleSet to the
     * specified <code>Digester</code> instance, associating them with
     * our namespace URI (if any).  This method should only be called
     * by a Digester instance.</p>
     *
     * @param digester Digester instance to which the new Rule instances
     *  should be added.
     */
    @Override
    public void addRuleInstances(Digester digester) {
        digester.addRule(fullPrefix,
                         new SetPublicIdRule("setPublicId"));
        digester.addRule(fullPrefix,
                         new IgnoreAnnotationsRule());
        digester.addRule(fullPrefix,
                new VersionRule());

        // Required for both fragments and non-fragments
        digester.addRule(fullPrefix + "/absolute-ordering", absoluteOrdering);
        digester.addRule(fullPrefix + "/ordering", relativeOrdering);

        if (fragment) {
            // web-fragment.xml
            digester.addRule(fullPrefix + "/name", name);
            digester.addCallMethod(fullPrefix + "/ordering/after/name",
                                   "addAfterOrdering", 0);
            digester.addCallMethod(fullPrefix + "/ordering/after/others",
                                   "addAfterOrderingOthers");
            digester.addCallMethod(fullPrefix + "/ordering/before/name",
                                   "addBeforeOrdering", 0);
            digester.addCallMethod(fullPrefix + "/ordering/before/others",
                                   "addBeforeOrderingOthers");
        } else {
            // web.xml
            digester.addCallMethod(fullPrefix + "/absolute-ordering/name",
                                   "addAbsoluteOrdering", 0);
            digester.addCallMethod(fullPrefix + "/absolute-ordering/others",
                                   "addAbsoluteOrderingOthers");
        }

        digester.addCallMethod(fullPrefix + "/context-param",
                               "addContextParam", 2);
        digester.addCallParam(fullPrefix + "/context-param/param-name", 0);
        digester.addCallParam(fullPrefix + "/context-param/param-value", 1);

        digester.addObjectCreate(fullPrefix + "/filter",
                                 "org.apache.catalina.deploy.FilterDef");
        digester.addSetNext(fullPrefix + "/filter",
                            "addFilter",
                            "org.apache.catalina.deploy.FilterDef");

        digester.addCallMethod(fullPrefix + "/filter/description",
                               "setDescription", 0);
        digester.addCallMethod(fullPrefix + "/filter/display-name",
                               "setDisplayName", 0);
        digester.addCallMethod(fullPrefix + "/filter/filter-class",
                               "setFilterClass", 0);
        digester.addCallMethod(fullPrefix + "/filter/filter-name",
                               "setFilterName", 0);
        digester.addCallMethod(fullPrefix + "/filter/icon/large-icon",
                               "setLargeIcon", 0);
        digester.addCallMethod(fullPrefix + "/filter/icon/small-icon",
                               "setSmallIcon", 0);
        digester.addCallMethod(fullPrefix + "/filter/async-supported",
                "setAsyncSupported", 0);

        digester.addCallMethod(fullPrefix + "/filter/init-param",
                               "addInitParameter", 2);
        digester.addCallParam(fullPrefix + "/filter/init-param/param-name",
                              0);
        digester.addCallParam(fullPrefix + "/filter/init-param/param-value",
                              1);

        digester.addObjectCreate(fullPrefix + "/filter-mapping",
                                 "org.apache.catalina.deploy.FilterMap");
        digester.addSetNext(fullPrefix + "/filter-mapping",
                                 "addFilterMapping",
                                 "org.apache.catalina.deploy.FilterMap");

        digester.addCallMethod(fullPrefix + "/filter-mapping/filter-name",
                               "setFilterName", 0);
        digester.addCallMethod(fullPrefix + "/filter-mapping/servlet-name",
                               "addServletName", 0);
        digester.addCallMethod(fullPrefix + "/filter-mapping/url-pattern",
                               "addURLPattern", 0);

        digester.addCallMethod(fullPrefix + "/filter-mapping/dispatcher",
                               "setDispatcher", 0);

         digester.addCallMethod(fullPrefix + "/listener/listener-class",
                                "addListener", 0);
         
     ...
    }

在這個方法里,可以看到熟悉的“/servlet/servlet-name”,"/listener/listener-class"等等。稍微懂點Digester解析語法的基礎的朋友,立刻可以知道這兒就是解析規則所在,Digester解析web.xml規則都是在此配置的。進一步梳理下,可以弄明白servlet,filter等重要對象的數據載體。

標簽
數據載體類
/filter
org.apache.catalina.deploy.FilterDef
/error-page
org.apache.catalina.deploy.ErrorPage
/servlet

org.apache.catalina.deploy.ServletDef

/filter-mappingorg.apache.catalina.deploy.FilterMap
/login-configorg.apache.catalina.deploy.LoginConfig
/session-configorg.apache.catalina.deploy.SessionConfig
...
...


部分私有內部Rule列表

死磕Tomcat7源碼之一:解析web.xml


通過分析,可以知道web.xml通過解析之后,配置信息都保存在WebXml對象中了。

WebXml中持有FilterMap,ServletDef,FilterDef等等對象的聚集信息。接下來tomcat就可以按照servlet規范初始化里面的組件了,有空將進一步介紹。


向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

广德县| 耿马| 馆陶县| 鄱阳县| 诸暨市| 晋州市| 河北省| 礼泉县| 文成县| 富宁县| 洮南市| 循化| 黔西县| 阿拉善盟| 从江县| 西乡县| 辽源市| 松江区| 安化县| 方城县| 南阳市| 东明县| 普兰店市| 六安市| 富锦市| 宁晋县| 偏关县| 清涧县| 柘城县| 扎兰屯市| 板桥市| 江川县| 宜黄县| 乌拉特后旗| 广州市| 启东市| 尖扎县| 义乌市| 襄城县| 营山县| 衡水市|