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的启动要做的主要的事情。。。
好像这里说的比较粗糙吧,因为这部分涉及到的东西实在太多了。。以后再来一点一点的分析吧。。。
- Tomcat源码分析之Context的创建与启动分析
- tomcat启动、request创建之分析
- ZeroMQ源码分析之Context
- tomcat源码分析三:tomcat启动与停止
- 传智播客Java web之 Tomcat的启动与批处理分析
- Tomcat源码阅读之Context启动
- Tomcat源码阅读之StandardEngine分析与Valve的设计
- Tomcat源码阅读之StandardHost与HostConfig的分析
- Hadoop源码分析之NameNode的启动与停止
- Hadoop源码分析之NameNode的启动与停止(续)
- Hadoop源码分析之DataNode的启动与停止
- Hadoop源码分析之DataNode的启动与停止
- TOMCAT源码分析(启动框架)
- TOMCAT源码分析(启动框架)
- TOMCAT源码分析(启动框架)
- TOMCAT源码分析(启动框架)
- TOMCAT源码分析(启动框架)
- TOMCAT源码分析(启动框架)
- Hive+MySQL的简介
- QTP无法录制的添加/删除对话框
- linux softirq 完全分析
- 大数据日志分析小例子
- The area面积计算
- Tomcat源码分析之Context的创建与启动分析
- 用手机连pc localhost 学习,调试网站
- WinCE文件目录定制及内存调整
- .net下如何引入和使用UEditor
- Standard - C 标准函数库
- [Liferay]Liferay 内存调整
- 2014年天勤计算机考研复试上机练习赛(2):世界杯来了
- Win8系统无法设置静态IP地址的解决方案
- Centos6.5屏幕分辨率调整