How Tomcat works之StandardContext 标准上下文

来源:互联网 发布:生化危机人工智能红后 编辑:程序博客网 时间:2024/06/11 21:16

回顾

就如在前面章节所看的,一个上下文代表一个web应用并包含了一个或者更多的wrapper,每个代表一个servlet定义。然而,一个上下文也需要其他的组件,尤其是加载器和管理器。这章演示了StandardContext类,基于接口Context实现。

 

首先我们将先看StandardContext对象的实例化和配置。之后讨论与其相关的类StandardContextMapper(在Tomcat 4中)和ContextConfig。下一步,我们查看每个来的HTTP请求的方法执行顺序。之后,再讨论StandardContext的重要属性。最后,讨论了Tomcat 5中的backgroundProcess方法。

 

StandardContextConfiguration

 

在一个StandardContext实例被构建后,它的start方法必须被调用使实例可以服务到来的HTTP请求。由于这样那样的原因,StandardContext对象可能启动失败。如果这种情况发生了,StandardContext对象的有效属性将被设置为false。course的有效属性标示了StandardContext的有效性。

 

启动成功,StandardContext对象必须被有效配置。在一个Tomcat 部署中,StandardContext的配置做大量的事情。这样context能够读和解析web.xml文件,位于%CATALINA_HOME%conf目录下并应用于所有的额应用部署。它也保证StandardContext实例能处理应用级别的web.xml文件。另外,configuration安装了一个校验值和证书值。

 

注意更多的StandardContext的configuration在第十五章中讨论

 

StandardContext类的属性中的一个是configurated属性,是一个boolean值用来指明StandardContext实例是否被合理配置。StandardContext使用好似一个时间监听器作为其配置器。当StandardContext实例的start方法被调用,其中一件事情是触发一个生命周期时间。这个事件调用监听器反过来将配置StandardContext实例。如果配置成功,监听器将设置configurated属性为true。否则,StandardContext将拒绝启动并不能服务HTTP请求。

 

在第十一章中,你看见一个生命周期接口的实现,添加到StandardContext实例中。它的类型是ch11.pyrmont.core.SimpleContextConfig并且仅仅简单地设置了StandardContext的configurated属性为true,而不用任何其他事情,仅仅就是欺骗StandardContext认为已经被合理配置。在一个Tomcat部署中,生命周期接口(用来配置StandardContext的)是一个ContextConfig类型,将在第十五章中讨论。

 

注意你理解了StandardContext配置的重要性。现在看看StandardContext的细节,从构造器的启动开始。

 

StandardContextClass的构造器

 

这里是StandardContext的构造器

 

publicStandardContext() { super(); pipeline.setBasic(new StandardContextValve());namingResources.setContainer(this); }

 

在上面构造器中需要注意的最重要的事情是StandardContext的pipeline,其被传入了一个StandardContextVlaue类型的的基本值。这个值将处理每个来自连接器的HTTP请求。

 

StartingStandardContext

 

Start方法初始化了StandardContext实例并使生命周期接口有机会配置StandardContext实例。这个监听器在配置StandardContext成功后设置configurated属性为true。结束时,start方法设置available属性为true或者false。True值意味着StandardContext实例已经被合理配置并且所有的子容器和组件已经成功启动。因此StandardContext实例已经准备服务即将到来的HTTP请求。False则表明相反。

 

StandardContext类安排一个叫做configurated的boolean值,初始化为false。如果生命周期接口成功完成了StandardContext的配置任务,configurated属性值将设置为true。在start方法的最后,StandardContext检查这个属性值。如果为true,这个StandardContext已经成功启动。否则,调用stop方法停止已经被start方法启动的组件。

 

在Tomcat 4中的start方法定义如下:

 

publicsynchronized void start() throws LifecycleException { if (started) throw newLifecycleException (sm.getString("containerBase.alreadyStarted",logName())); if (debug >= 1) log("Starting");

// Notify ourinterested LifecycleListeners lifecycle.fireLifecycleEvent(BEFORE_START_EVENT,null); if (debug >= 1) log("Processing start(), currentavailable=" + getAvailable()); setAvailable(false); setConfigured(false);boolean ok = true; // Add missing components as necessary if (getResources() ==null) { // (1) Required by Loader

 

if (debug >= 1)log("Configuring default Resources"); try { if ((docBase != null)&& (docBase.endsWith(".war"))) setResources(newWARDirContext()); else setResources(new FileDirContext()); } catch(IllegalArgumentException e) { log("Error initializing resources: " +e.getMessage()); ok = false; } }

 

if (ok &&(resources instanceof ProxyDirContext)) { DirContext dirContext =((ProxyDirContext) resources).getDirContext(); if ((dirContext != null)&& (dirContext instanceof BaseDirContext)) { ((BaseDirContext) dirContext).setDocBase(getBasePath());((BaseDirContext) dirContext).allocate(); } }

 

if (getLoader() ==null) { // (2) Required by Manager if (getPrivileged()) { if (debug >= 1)log("Configuring privileged default Loader"); setLoader(newWebappLoader(this.getClass().getClassLoader())); } else { if (debug >= 1)log("Configuring non-privileged default Loader"); setLoader(newWebappLoader(getParentClassLoader())); } }

 

if (getManager()== null) { // (3) After prerequisites if (debug >= 1) log("Configuringdefault Manager"); setManager(new StandardManager()); }

 

// Initializecharacter set mapper

getCharsetMapper();

 

// Post workdirectory

 

postWorkDirectory();

 

// Reading the"catalina.useNaming" environment variable

 

StringuseNamingProperty = System.getProperty("catalina.useNaming"); if((useNamingProperty != null) &&(useNamingProperty.equals("false"))) { useNaming = false; }

 

if (ok &&isUseNaming()) { if (namingContextListener == null) { namingContextListener =new NamingContextListener(); namingContextListener.setDebug(getDebug());

namingContextListener.setName(getNamingContextName());addLifecycleListener(namingContextListener); } }

 

// Binding thread

ClassLoader oldCCL= bindThread();

 

// Standardcontainer startup

if (debug >= 1)log("Processing standard container startup");

 

if (ok) {

  try {

addDefaultMapper(this.mapperClass);

started = true;

// Start our subordinate components, if any

if ((loader != null) && (loader instanceofLifecycle))

((Lifecycle) loader).start();

 

// Unbinding thread

unbindThread(oldCCL);

 

// Binding thread

oldCCL = bindThread();

 

if ((cluster != null) && (cluster instanceofLifecycle)) ((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 thebasic),

// if any
if (pipeline instanceof Lifecycle) ((Lifecycle) pipeline).start();

// Notify our interested LifecycleListeners

lifecycle.fireLifecycleEvent(START_EVENT, null);

 

if ((manager != null) && (manager instanceofLifecycle)) ((Lifecycle) manager).start();

}

finally { // Unbinding thread unbindThread(oldCCL); }}

if (!getConfigured()) ok = false;

 

// We put the resources into the servlet context

if (ok) getServletContext().setAttribute(Globals.RESOURCES_ATTR, getResources());

// Binding thread

oldCCL = bindThread();

// Create context attributes that will be required

if (ok) { if (debug >= 1) log("Postingstandard context attributes"); postWelcomeFiles(); }

// Configure and call application event listeners andfilters

if (ok) { if (!listenerStart())

ok = false; }

 

if (ok) { if (!filterStart()) ok = false; }

 

// Load and initialize all "load on startup"servlets

if (ok) loadOnStartup(findChildren());

// Unbinding thread

unbindThread(oldCCL);

// Set available status depending upon startup success

 

if (ok) { if (debug >= 1) log("Startingcompleted"); setAvailable(true); } else {log(sm.getString("standardContext.startFailed")); try { stop(); }catch (Throwable t) {log(sm.getString("standardContext.startCleanup"), t); } setAvailable(false);}

// Notify ourinterested LifecycleListenerslifecycle.fireLifecycleEvent(AFTER_START_EVENT, null); }

 

 

注意 在Tomcat 5中的start方法与Tomcat 4的start方法相似。然而,其包含了JMX相关的代码。JMX将在第20章中讲解。

 

Start方法将完成一系列事情

 

  1  触发BEFORE_START时间

  2  设置availability属性为false

  3  设置configurated属性为false

  4  设置资源

  5  设置加载器

  6  设置管理器

  7  初始化字符设置映射

  8  启动与context相关的其他组件

  9  启动子容器(比如wrapper)

  10 启动管道

  11 启动管理器

  12 触发START事件。这里监听器(ContextConfig)将处理一些配置操作(在第十五章中讨论)。在成功配置后,ContextConfig将设置StandardContext的configurated属性为true

  13 检查configurated属性值。如果是true,做一下事情:调用postWelcomepages方法,加载子wrappres,需要在start-up的时候加载,并设置availabilty属性为true。如果configurated为false,调用stop方法。

  14 触发AFLTER_START事件


0 0
原创粉丝点击