1. 程式人生 > >How Tomcat Works 12: StandardContext

How Tomcat Works 12: StandardContext

    1. StandardContext的配置     (1)啟動:start()方法呼叫後,如果context例項失敗,需要將available設為false     (2)Tomcat部署context時:會先讀取解析%CATALINA_HOME%/conf內的web.xml為所有standardContext,而後會讀取解析webapp-level級別的web.xml。此外,authenticator和certicate valve的安裝。     (3)StandardContext使用event Listener作為configurator,當所有listener event呼叫完成,則需要把configured property設定為true。如果配置失敗,則StandardContext例項會拒絕啟動     (4)使用了StandardContextConfig【實現了Lifecycle Listener介面】類     2. StandardContext解析:     (1)構造器:             pipeline加入standardContextValve,處理所有connector過來的http request       

 public StandardContext() {
            super();
            pipeline.setBasic(new StandardContextValve()); // StandardContextValve 處理所有的從connector過來的http request
            namingResources.setContainer(this);
        }

    (2)啟動StandardContext             啟動方法初始化context例項,讓所有lifecycle listener有機會完成配置。配置成功會設定available=true,為所有http request提供服務             Tomcat4中的start方法實現           

 @Override
            public void start() throws LifecycleException {
                if(started) {
                    throw new LifecycleException("containerBase.alreadyStarted");
                }
                lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);
                setAvailable(false);
                setConfigured(false);
                boolean ok = true;
                
                // (1)設定Loader需要的資源路徑
                if ((docBase != null) && (docBase.endsWith(".war"))) {
                    setResources(new WARDirContext());
                }else {
                    setResources(new FileDirContext());
                }
                 
                // (2)set Loader和Manager(session管理)
                if (getPrivileged()) {
                    setLoader(new WebappLoader(this.getClass().getClassLoader()));
                }esle{
                    setLoader(new WebappLoader(getParentClassLoader()));
                }
                setManager(new StandardManager());
                // Initialize character set mapper
                 getCharsetMapper();
                 // Post work directory
                 postWorkDirectory();
                 
                 // (3)如果都配置完成,使用namingContextListener設定配置項
                  if (ok && isUseNaming()) {
                     if (namingContextListener == null) {
                         namingContextListener = new NamingContextListener();
                         namingContextListener.setName(getNamingContextName());
                         addLifecycleListener(namingContextListener);
                    }
                     
                     // Binding thread
                     ClassLoader oldCCL = bindThread();
                     
                // (4)啟動loader,logger,解綁執行緒-》繫結執行緒,啟動mapper,啟動子容器,啟動pipeline,觸發startevent,啟動manager
                     if (ok) {
                         try {
                             addDefaultMapper(this.mapperClass);
                             started = true;
                             // Start our subordinate components, if any
                             if ((loader != null) && (loader instanceof Lifecycle))
                                 ((Lifecycle) loader).start();
                             if ((logger != null) && (logger instanceof Lifecycle))
                                 ((Lifecycle) logger).start();
                             // Unbinding thread
                             unbindThread(oldCCL);
                             // Binding thread
                             oldCCL = bindThread();
                             if ((cluster != null) && (cluster instanceof Lifecycle))
                                 ((Lifecycle) cluster).start();
                             if ((realm != null) && (realm instanceof Lifecycle))
                                 ((Lifecycle) realm).start();
                             if ((resources != null) && (resources instanceof Lifecycle))
                                 ((Lifecycle) resources).start();
                             // Start our Mappers, if any
                             Mapper mappers[] = findMappers();
                             for (int i = 0; i < mappers.length; i++) {
                                 if (mappers[i] instanceof Lifecycle)
                                     ((Lifecycle) mappers[i]).start();
                             }
                             // Start our child containers, if any
                             Container children[] = findChildren();
                             for (int i = 0; i < children.length; i++) {
                                 if (children[i] instanceof Lifecycle)
                                     ((Lifecycle) children[i]).start();
                                 }
                             // Start the Valves in our pipeline (including the basic),
                             // if any
                             if (pipeline instanceof Lifecycle)
                                 ((Lifecycle) pipeline).start();
                             // Notify our interested LifecycleListeners
                             lifecycle.fireLifecycleEvent(START_EVENT, null);
                             if ((manager != null) && (manager instanceof Lifecycle))
                                 ((Lifecycle) manager).start();
                             }     finally {
                             // Unbinding thread
                                 unbindThread(oldCCL);
                             }
                         }
                     
                     // (5) 如果完成,載入啟動引數給servlets
                     if (!getConfigured())
                         ok = false;
                     // Load and initialize all "load on startup" servlets
                     if (ok)
                         loadOnStartup(findChildren());
                     // Unbinding thread
                     unbindThread(oldCCL);
                     lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
            }

        (3)invoke方法:             【若有】被Host.invoke呼叫或者connector中呼叫invoke.呼叫前會檢視是否重啟中                

public void invoke(Request request, Response response) throws IOException, ServletException {
                     // Wait if we are reloading
                     while (getPaused()) {             
                         Thread.sleep(1000);                
                         // Normal request processing
                         if (swallowOutput) {                
                             SystemLogHandler.startCapture();
                             super.invoke(request, response);                    
                             String log = SystemLogHandler.stopCapture();
                             if (log != null && log.length() > 0) {
                                 log(log);
                             }
                        }
                     }
                     else {
                         super.invoke(request, response);
                     }
                }

        (4)支援reload             在WebAppLoad.setContainer中會加入setReloadable(container.getReloadable()),             setReloadable會根據true/false選擇threadStart()或threadStop()間隔掃描WEB-INF中的class和jar包             如果有變化,會在context中解除安裝原有的classLoader,然後所有wrapper.stop() 然後再重啟wrapper.start()->這是wrapper的getClassLoader會變成新的classloader,同時所有servlet class都會從新allocate