1. 程式人生 > >Tomcat8.5原始碼分析-StandardContext

Tomcat8.5原始碼分析-StandardContext

StandardContext

直接看程式碼,相關操作已經打上註釋:

protected synchronized void startInternal() throws LifecycleException {

        if(log.isDebugEnabled())
            log.debug("Starting " + getBaseName());

        // Send j2ee.state.starting notification
        //傳送正在啟動的通知
        if (this.getObjectName() != null
) { Notification notification = new Notification("j2ee.state.starting", this.getObjectName(), sequenceNumber.getAndIncrement()); broadcaster.sendNotification(notification); } setConfigured(false); boolean ok = true; // Currently this is effectively a NO-OP but needs to be called to
// ensure the NamingResources follows the correct lifecycle //啟動context維護的JNDI資源 if (namingResources != null) { namingResources.start(); } // Add missing components as necessary if (getResources() == null) { // (1) Required by Loader if
(log.isDebugEnabled()) log.debug("Configuring default Resources"); try { setResources(new StandardRoot(this));//初始化當前的webResourceRoot } catch (IllegalArgumentException e) { log.error(sm.getString("standardContext.resourcesInit"), e); ok = false; } } if (ok) { resourcesStart();//啟動當前的webRecourseRoot,主要用於類載入和按照路徑查詢資原始檔 } //建立web應用載入器 if (getLoader() == null) { WebappLoader webappLoader = new WebappLoader(getParentClassLoader()); webappLoader.setDelegate(getDelegate()); setLoader(webappLoader); } // An explicit cookie processor hasn't been specified; use the default //如果沒有指定一個明確的cookie,使用預設的 if (cookieProcessor == null) { cookieProcessor = new Rfc6265CookieProcessor(); } // Initialize character set mapper //初始化字符集對映 getCharsetMapper(); // Post work directory //傳遞工作目錄 postWorkDirectory(); // Validate required extensions boolean dependencyCheck = true; try { dependencyCheck = ExtensionValidator.validateApplication (getResources(), this); } catch (IOException ioe) { log.error(sm.getString("standardContext.extensionValidationError"), ioe); dependencyCheck = false; } //web應用的依賴檢測,主要用來檢測依賴拓展點的完整性 if (!dependencyCheck) { // do not make application available if dependency check fails ok = false; } // Reading the "catalina.useNaming" environment variable String useNamingProperty = System.getProperty("catalina.useNaming"); if ((useNamingProperty != null) && (useNamingProperty.equals("false"))) { useNaming = false; } //如果當前context使用了JNDI,就為它新增監聽器NamingContextListener if (ok && isUseNaming()) { if (getNamingContextListener() == null) { NamingContextListener ncl = new NamingContextListener(); ncl.setName(getNamingContextName()); ncl.setExceptionOnFailedWrite(getJndiExceptionOnFailedWrite()); addLifecycleListener(ncl); setNamingContextListener(ncl); } } // Standard container startup if (log.isDebugEnabled()) log.debug("Processing standard container startup"); // Binding thread //繫結執行緒 ClassLoader oldCCL = bindThread(); try { if (ok) { // Start our subordinate components, if any //開始我們的下一級別元件,如果有 Loader loader = getLoader(); if (loader instanceof Lifecycle) { ((Lifecycle) loader).start();//啟動webAppLoader } // since the loader just started, the webapp classloader is now // created. setClassLoaderProperty("clearReferencesRmiTargets", getClearReferencesRmiTargets()); setClassLoaderProperty("clearReferencesStopThreads", getClearReferencesStopThreads()); setClassLoaderProperty("clearReferencesStopTimerThreads", getClearReferencesStopTimerThreads()); setClassLoaderProperty("clearReferencesHttpClientKeepAliveThread", getClearReferencesHttpClientKeepAliveThread()); // By calling unbindThread and bindThread in a row, we setup the // current Thread CCL to be the webapp classloader unbindThread(oldCCL); oldCCL = bindThread(); // Initialize logger again. Other components might have used it // too early, so it should be reset. logger = null; getLogger(); Realm realm = getRealmInternal(); if(null != realm) { if (realm instanceof Lifecycle) { ((Lifecycle) realm).start();//啟動安全元件 } // Place the CredentialHandler into the ServletContext so // applications can have access to it. Wrap it in a "safe" // handler so application's can't modify it. CredentialHandler safeHandler = new CredentialHandler() { @Override public boolean matches(String inputCredentials, String storedCredentials) { return getRealmInternal().getCredentialHandler().matches(inputCredentials, storedCredentials); } @Override public String mutate(String inputCredentials) { return getRealmInternal().getCredentialHandler().mutate(inputCredentials); } }; context.setAttribute(Globals.CREDENTIAL_HANDLER, safeHandler); } // Notify our interested LifecycleListeners //通知我們的相關的生命監聽器 fireLifecycleEvent(Lifecycle.CONFIGURE_START_EVENT, null);//觸發生命週期監聽器 // Start our child containers, if not already started for (Container child : findChildren()) { if (!child.getState().isAvailable()) { child.start();//啟動context的子節點wrapper } } // Start the Valves in our pipeline (including the basic), // if any if (pipeline instanceof Lifecycle) { ((Lifecycle) pipeline).start();//啟動context所維護的pipeline } // Acquire clustered manager //建立會話管理器,如果有叢集,由叢集配置,否則由StandardManager() Manager contextManager = null; Manager manager = getManager(); if (manager == null) { if (log.isDebugEnabled()) { log.debug(sm.getString("standardContext.cluster.noManager", Boolean.valueOf((getCluster() != null)), Boolean.valueOf(distributable))); } if ( (getCluster() != null) && distributable) { try { contextManager = getCluster().createManager(getName()); } catch (Exception ex) { log.error("standardContext.clusterFail", ex); ok = false; } } else { contextManager = new StandardManager(); } } // Configure default manager if none was specified //如果沒有被指定配置預設的會話管理器 if (contextManager != null) { if (log.isDebugEnabled()) { log.debug(sm.getString("standardContext.manager", contextManager.getClass().getName())); } setManager(contextManager); } if (manager!=null && (getCluster() != null) && distributable) { //let the cluster know that there is a context that is distributable //and that it has its own manager getCluster().registerManager(manager); } } if (!getConfigured()) { log.error(sm.getString("standardContext.configurationFail")); ok = false; } // We put the resources into the servlet context //我們把資源(WebResourceRoot裡面的資源)放到servletContext裡面去 if (ok) getServletContext().setAttribute (Globals.RESOURCES_ATTR, getResources()); if (ok ) { if (getInstanceManager() == null) { javax.naming.Context context = null; if (isUseNaming() && getNamingContextListener() != null) { context = getNamingContextListener().getEnvContext(); } Map<String, Map<String, String>> injectionMap = buildInjectionMap( getIgnoreAnnotations() ? new NamingResourcesImpl(): getNamingResources()); setInstanceManager(new DefaultInstanceManager(context, injectionMap, this, this.getClass().getClassLoader()));//建立例項物件管理器,用於建立例項物件,如servlet,Filter } getServletContext().setAttribute( InstanceManager.class.getName(), getInstanceManager()); InstanceManagerBindings.bind(getLoader().getClassLoader(), getInstanceManager()); } // Create context attributes that will be required //將jar包掃描器放到ServletContext的屬性裡面去 if (ok) { getServletContext().setAttribute( JarScanner.class.getName(), getJarScanner()); } // Set up the context init params //合併ServletContext引數和ApplicationParmeter的引數 mergeParameters(); // Call ServletContainerInitializers新增web應用的配置,如servlet,Filter //呼叫這個方法以可程式設計的方式新增 for (Map.Entry<ServletContainerInitializer, Set<Class<?>>> entry : initializers.entrySet()) { try { entry.getKey().onStartup(entry.getValue(), getServletContext()); } catch (ServletException e) { log.error(sm.getString("standardContext.sciFail"), e); ok = false; break; } } // Configure and call application event listeners //例項化應用監聽器 if (ok) { if (!listenerStart()) { log.error(sm.getString("standardContext.listenerFail")); ok = false; } } // Check constraints for uncovered HTTP methods // Needs to be after SCIs and listeners as they may programmatically // change constraints //檢測未覆蓋的http方法的安全約束 if (ok) { checkConstraintsForUncoveredMethods(findConstraints()); } try { // Start manager //啟動會話管理器 Manager manager = getManager(); if (manager instanceof Lifecycle) { ((Lifecycle) manager).start(); } } catch(Exception e) { log.error(sm.getString("standardContext.managerFail"), e); ok = false; } // Configure and call application filters //配置並且呼叫應用過濾器 if (ok) { if (!filterStart()) { log.error(sm.getString("standardContext.filterFail")); ok = false; } } // Load and initialize all "load on startup" servlets //例項化servlet if (ok) { if (!loadOnStartup(findChildren())){ log.error(sm.getString("standardContext.servletFail")); ok = false; } } // Start ContainerBackgroundProcessor thread //開始後臺的程序 super.threadStart(); } finally { // Unbinding thread unbindThread(oldCCL); } // Set available status depending upon startup success if (ok) { if (log.isDebugEnabled()) log.debug("Starting completed"); } else { log.error(sm.getString("standardContext.startFailed", getName())); } startTime=System.currentTimeMillis(); // Send j2ee.state.running notification //釋出正在執行的JMX通知 if (ok && (this.getObjectName() != null)) { Notification notification = new Notification("j2ee.state.running", this.getObjectName(), sequenceNumber.getAndIncrement()); broadcaster.sendNotification(notification); } // The WebResources implementation caches references to JAR files. On // some platforms these references may lock the JAR files. Since web // application start is likely to have read from lots of JARs, trigger // a clean-up now. //釋放資源 getResources().gc(); // Reinitializing if something went wrong if (!ok) { setState(LifecycleState.FAILED); } else { setState(LifecycleState.STARTING); } }

看這一行程式碼,觸發了生命週期事件,這個監聽器是ContextConfig,相關操作在ContextConfig章節裡面進行分析。
這裡寫圖片描述
再看這一行程式碼,初始化了servlet
這裡寫圖片描述
看load on startup這個方法:

public boolean loadOnStartup(Container children[]) {

        // Collect "load on startup" servlets that need to be initialized
        TreeMap<Integer, ArrayList<Wrapper>> map = new TreeMap<>();
        for (int i = 0; i < children.length; i++) {
            Wrapper wrapper = (Wrapper) children[i];
            int loadOnStartup = wrapper.getLoadOnStartup();
            if (loadOnStartup < 0)
                continue;
            Integer key = Integer.valueOf(loadOnStartup);
            ArrayList<Wrapper> list = map.get(key);
            if (list == null) {
                list = new ArrayList<>();
                map.put(key, list);
            }
            list.add(wrapper);
        }

        // Load the collected "load on startup" servlets
        for (ArrayList<Wrapper> list : map.values()) {
            for (Wrapper wrapper : list) {
                try {
                    wrapper.load();/*例項化servlet並對servlet進行初始化*/
                } catch (ServletException e) {
                    getLogger().error(sm.getString("standardContext.loadOnStartup.loadException",
                          getName(), wrapper.getName()), StandardWrapper.getRootCause(e));
                    // NOTE: load errors (including a servlet that throws
                    // UnavailableException from the init() method) are NOT
                    // fatal to application startup
                    // unless failCtxIfServletStartFails="true" is specified
                    if(getComputedFailCtxIfServletStartFails()) {
                        return false;
                    }
                }
            }
        }
        return true;

    }