Tomcat源码分析之Context的创建与启动分析

来源:互联网 发布:南昌大学网络教育平台 编辑:程序博客网 时间:2024/05/16 09:54

在前面的文章中,知道在HostConfig对象中,会在host启动的时候开始部署当前host下面的web应用程序,一般情况下就是扫描webapps文件夹,然后为每个web应用程序创建Context对象,一般情况下也就是StandardContext。。

这里其实一个Context也就代表了一个web应用程序,它具体来维护应用程序定义的servlet,filter,资源。。。

但是这里由于Context接口实在比较大,不好挨个挨个字段都贴出来,这里就先来看看StandardContext的创建与启动的过程吧,先来看看构造函数:

    public StandardContext() {        super();        pipeline.setBasic(new StandardContextValve());  //在pipeline上添加basic的valve        broadcaster = new NotificationBroadcasterSupport();        // Set defaults        if (!Globals.STRICT_SERVLET_COMPLIANCE) {            // Strict servlet compliance requires all extension mapped servlets            // to be checked against welcome files            resourceOnlyServlets.add("jsp");        }    }

这里主要是在当前pipeline上面添加了一个basic格式的valve对象。。。还有其他的一些事情。。。接下来来看看初始化吧:

    protected void initInternal() throws LifecycleException {        super.initInternal();        // Register the naming resources        if (namingResources != null) {            namingResources.init();        }        if (resources != null) {            resources.start();  //启动本地资源        }        // Send j2ee.object.created notification        if (this.getObjectName() != null) {            Notification notification = new Notification("j2ee.object.created",                    this.getObjectName(), sequenceNumber.getAndIncrement());            broadcaster.sendNotification(notification);        }    }

这里主要还是进行资源的初始化吧。。。那么接下来来看看启动的方法吧:

    //启动context,这里可以理解为启动一个应用程序    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);  //还没有开始config        boolean ok = true;  //必须保证每一步都ok        // Currently this is effectively a NO-OP but needs to be called to        // ensure the NamingResources follows the correct lifecycle        if (namingResources != null) {            namingResources.start();        }        //resource部分        // 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));  //创建资源引用            } catch (IllegalArgumentException e) {                log.error("Error initializing resources: " + e.getMessage());                ok = false;            }        }        if (ok) {            resourcesStart();         }        //loader部分        if (getLoader() == null) { //这一步用于创建loader对象            WebappLoader webappLoader = new WebappLoader(getParentClassLoader());    //这里用于创建当前context用的classLoader,这里会将parent设置为sharedclassLoader            webappLoader.setDelegate(getDelegate());              setLoader(webappLoader);  //保存创建的loader        }        // Initialize character set mapper        getCharsetMapper();  //charsetmapper        // Post work directory        postWorkDirectory();        // Validate required extensions        boolean dependencyCheck = true;        try {  //扩展名检查            dependencyCheck = ExtensionValidator.validateApplication                (getResources(), this);        } catch (IOException ioe) {            log.error("Error in dependencyCheck", ioe);            dependencyCheck = false;        }        if (!dependencyCheck) {            // do not make application available if depency check fails            ok = false;        }        // Reading the "catalina.useNaming" environment variable        String useNamingProperty = System.getProperty("catalina.useNaming");        if ((useNamingProperty != null)            && (useNamingProperty.equals("false"))) {            useNaming = false;        }        if (ok && isUseNaming()) {            if (getNamingContextListener() == null) {                NamingContextListener ncl = new NamingContextListener();  //创建一个NamingContextListener,并将其加入到listeneres里面去                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();  //获取loader                if ((loader != null) && (loader instanceof Lifecycle))                    ((Lifecycle) loader).start();   //启动当前web应用程序的loader                // since the loader just started, the webapp classloader is now                // created.                //设置loader的一些参数                setClassLoaderProperty("clearReferencesStatic",                        getClearReferencesStatic());                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();                Cluster cluster = getClusterInternal();                if ((cluster != null) && (cluster instanceof Lifecycle))                    ((Lifecycle) cluster).start();                Realm realm = getRealmInternal();                if ((realm != null) && (realm instanceof Lifecycle))                    ((Lifecycle) realm).start();                // Notify our interested LifecycleListeners                fireLifecycleEvent(Lifecycle.CONFIGURE_START_EVENT, null);  //通知监听,激活config启动的事件,这里会在contextConfig里面执行xml文件的解析等工作                // Start our child containers, if not already started                for (Container child : findChildren()) {  //启动所有的child,其实这里主要是启动wrapper对象                    if (!child.getState().isAvailable()) {                        child.start();                    }                }                // Start the Valves in our pipeline (including the basic),                // if any                if (pipeline instanceof Lifecycle) {                    ((Lifecycle) pipeline).start();   //启动pipeline                }                // Acquire clustered manager                Manager contextManager = null;                Manager manager = getManager();  //创建manager对象,这个主要是跟session相关的吧                if (manager == null) {                    if (log.isDebugEnabled()) {                        log.debug(sm.getString("standardContext.cluster.noManager",                                Boolean.valueOf((getCluster() != null)),                                Boolean.valueOf(distributable)));                    }                    if ( (getCluster() != null) && distributable) {  //这里要根据是否有集群的配置来设置manager对象                        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( "Error getConfigured");                ok = false;            }            // We put the resources into the servlet context            if (ok)                getServletContext().setAttribute                    (Globals.RESOURCES_ATTR, getResources());   //在servletcontext里面保存整个web应用程序的rootresource,可以用于加载文件什么的            if (ok ) {  //接下来主要是创建instancemanager,它用于负责管理当前web应用程序对象的实例化                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,    //创建instancemanager                            injectionMap, this, this.getClass().getClassLoader()));                    getServletContext().setAttribute(                            InstanceManager.class.getName(), getInstanceManager());                }            }            // Create context attributes that will be required            if (ok) {  //设置jar包的扫描                getServletContext().setAttribute(                        JarScanner.class.getName(), getJarScanner());            }            // Set up the context init params            mergeParameters();  //合并context的一些初始化参数            // Call ServletContainerInitializers            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()) {  //启动contextListener啥的                    log.error( "Error listenerStart");                    ok = false;                }            }            // Check constraints for uncovered HTTP methods            // Needs to be after SCIs and listeners as they may programatically            // change constraints            if (ok) {                checkConstraintsForUncoveredMethods(findConstraints());            }            try {                // Start manager                Manager manager = getManager();                if ((manager != null) && (manager instanceof Lifecycle)) {                    ((Lifecycle) getManager()).start();   //启动manager对象                }            } catch(Exception e) {                log.error("Error manager.start()", e);                ok = false;            }            // Configure and call application filters            if (ok) {                if (!filterStart()) {                    log.error("Error filterStart");                    ok = false;                }            }            // Load and initialize all "load on startup" servlets            if (ok) {                loadOnStartup(findChildren());  //如果有load on startup的话,需要启动            }            // 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        if (ok && (this.getObjectName() != null)) {            Notification notification =                new Notification("j2ee.state.running", this.getObjectName(),                                 sequenceNumber.getAndIncrement());            broadcaster.sendNotification(notification);        }        // Reinitializing if something went wrong        if (!ok) {            setState(LifecycleState.FAILED);        } else {            setState(LifecycleState.STARTING);        }    }

这部分代码够长的吧,这里将要做的工作归纳如下:

(1)设置当前web应用程序的资源引用,StandardRoot对象,可以用它来载入当前应用程序的资源。例如文件什么的。

(2)创建WebappLoader对象,内部还会创建WebAppClassLoader对象,具体这个是干嘛的,应该从名字猜也能猜出来吧,并启动

(3)激活CONFIGURE_START_EVENT事件,前面的文章已经交代过在context创建时会附带给其加一个listener,这个listener就是ContextConfig,它会响应CONFIGURE_START_EVENT事件,其实就是开始读取配置,包括servlet的定义什么,并将读取到的信息加入到当前context对象中。。

(4)启动刚刚通过处理配置文件得到的对象。例如wrapper,用于包装servlet。

(5)创建manager并启动,它用于处理session相关的工作

(6)在servletContext对象中设置一些属性

(7)初始化各种listener,例如定义的contextListener啥的


上面就是Context的启动要做的主要的事情。。。


好像这里说的比较粗糙吧,因为这部分涉及到的东西实在太多了。。以后再来一点一点的分析吧。。。

1 0
原创粉丝点击