StandardContext类 
  Context实例代表着一个具体的web应用程序,其中包含一个或者多个Wrapper实例,每个Wrapper实例代表着具体的servlet定义。但是,Context容器还需要其他组件支持,典型的如载入器和session管理器。

          

在创建了StandardContext实例后,必须调用其startInternal方法。 
(1)发送启动状态通知。

// Send j2ee.state.starting notification
if (this.getObjectName() != null) {
Notification notification = new Notification("j2ee.state.starting",
this.getObjectName(), sequenceNumber.getAndIncrement());
broadcaster.sendNotification(notification);
}

(2)设置配置状态

setConfigured(false);
public void setConfigured(boolean configured) {
boolean oldConfigured = this.configured;
this.configured = configured;
support.firePropertyChange("configured",
oldConfigured,
this.configured);
}

(3)加载资源

if (webappResources == null) {   // (1) Required by Loader
if (log.isDebugEnabled())
log.debug("Configuring default Resources");
try {
if (getDocBase() == null)
setResources(new EmptyDirContext());
else if ((getDocBase() != null) && (getDocBase().endsWith(".war")) &&
(!(new File(getBasePath())).isDirectory()))
setResources(new WARDirContext());
else
setResources(new FileDirContext());
} catch (IllegalArgumentException e) {
log.error(sm.getString("standardContext.resourcesInit"), e);
ok = false;
}
}

(4)初始化字符集mapper

// Initialize character set mapper
getCharsetMapper();

(5)设置工作目录

// Post work directory
postWorkDirectory();

6)绑定线程

// Binding thread
ClassLoader oldCCL = bindThread();

(7)通知监听器,启动子容器,开启管道中的阀门

// 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();
}
}
// Start the Valves in our pipeline (including the basic),
// if any
if (pipeline instanceof Lifecycle) {
((Lifecycle) pipeline).start();
}

(8)加载资源到servletContext和资源映射

// We put the resources into the servlet context
if (ok)
getServletContext().setAttribute
(Globals.RESOURCES_ATTR, getResources());
// Initialize associated mapper
mapper.setContext(getPath(), welcomeFiles, resources);

(9)创建context属性设置初始参数

// Create context attributes that will be required
if (ok) {
getServletContext().setAttribute(
JarScanner.class.getName(), getJarScanner());
} // Set up the context init params
mergeParameters();

(10)servlet容器初始化,配置事件监听

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;
}
}

(11)启动Manager

 try {
// Start manager
if ((manager != null) && (manager instanceof Lifecycle)) {
((Lifecycle) getManager()).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
if (ok) {
if (!loadOnStartup(findChildren())){
log.error(sm.getString("standardContext.servletFail"));
ok = false;
}
} // Start ContainerBackgroundProcessor thread
super.threadStart();

(12)通知启动状态,重新检查是否启动成功。

// Send j2ee.state.running notification
if (ok && (this.getObjectName() != null)) {
Notification notification =
new Notification("j2ee.state.running", this.getObjectName(),
sequenceNumber.getAndIncrement());
broadcaster.sendNotification(notification);
} // Close all JARs right away to avoid always opening a peak number
// of files on startup
if (getLoader() instanceof WebappLoader) {
((WebappLoader) getLoader()).closeJARs(true);
} // Reinitializing if something went wrong
if (!ok) {
setState(LifecycleState.FAILED);
} else {
setState(LifecycleState.STARTING);
}

StandardContextValve类 
实现了一个默认的阀门类,对于每一个HTTP请求可能是有用的。重要的方法invoke。 
(1)WEB-INF或META-INF目录下的资源访问不了的原因

// Disallow any direct access to resources under WEB-INF or META-INF
MessageBytes requestPathMB = request.getRequestPathMB();
if ((requestPathMB.startsWithIgnoreCase("/META-INF/", 0))
|| (requestPathMB.equalsIgnoreCase("/META-INF"))
|| (requestPathMB.startsWithIgnoreCase("/WEB-INF/", 0))
|| (requestPathMB.equalsIgnoreCase("/WEB-INF"))) {
response.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}

(2)获取一个Wrapper

// Select the Wrapper to be used for this Request
Wrapper wrapper = request.getWrapper();
if (wrapper == null || wrapper.isUnavailable()) {
response.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}

(3)认证request请求,调用Wrapper的阀门(valve)

// Acknowledge the request
try {
response.sendAcknowledgement();
} catch (IOException ioe) {
container.getLogger().error(sm.getString(
"standardContextValve.acknowledgeException"), ioe);
request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, ioe);
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
return;
} if (request.isAsyncSupported()) {
request.setAsyncSupported(wrapper.getPipeline().isAsyncSupported());
}
wrapper.getPipeline().getFirst().invoke(request, response);

StandardContext对重载的支持 
        在类加载的指定的仓库下,类发生了改变或者web.xml文件发生了改变将会被重新加载,然而,不能处理任何context.xml文件的改变,如果context.xml发生了改变,应该停止指定的上下文(Context),并且创建和启动一个新的Context实例代替。 
在StandardContext中的reload方法中 
(1)检查组件是否可用

// Validate our current component state
if (!getState().isAvailable())
throw new IllegalStateException
(sm.getString("standardContext.notStarted", getName()));
if(log.isInfoEnabled())
log.info(sm.getString("standardContext.reloadingStarted",
getName()));

(2)设置StandardContext暂停状态

// Stop accepting requests temporarily.
setPaused(true);

(3)停止并启动

try {
stop();
} catch (LifecycleException e) {
log.error(
sm.getString("standardContext.stoppingContext", getName()), e);
} try {
start();
} catch (LifecycleException e) {
log.error(
sm.getString("standardContext.startingContext", getName()), e);
}

(4)设置StandardContext暂停状态

setPaused(false);//设置非暂停状态

ContainerBackgroundProcessor类 
        Context容器运行还需要其他的组件支持,例如载入器和session管理器。通常这些组件都需要各自的线程执行一些后台处理任务。例如:载入器使用线程定时的检查类和jar的时间戳是否发生改变;session管理器使用线程定时检查session是否过期。 
        为了节省资源,所有后台共享同一个线程。若某个组件或者servlet容器需要周期性的执行一个操作,只需要将代码写到backgroundProcess方法中。 
ContainerBackgroundProcessor是ContainerBase的内部类,下面是代码:

protected class ContainerBackgroundProcessor implements Runnable {

        @Override
public void run() {
Throwable t = null;
String unexpectedDeathMessage = sm.getString(
"containerBase.backgroundProcess.unexpectedThreadDeath",
Thread.currentThread().getName());
try {
while (!threadDone) {
try {
//sleep指定时间
Thread.sleep(backgroundProcessorDelay * 1000L);
} catch (InterruptedException e) {
// Ignore
}
if (!threadDone) {
Container parent = (Container) getMappingObject();
ClassLoader cl =
Thread.currentThread().getContextClassLoader();
if (parent.getLoader() != null) {
cl = parent.getLoader().getClassLoader();
}
processChildren(parent, cl);
}
}
} catch (RuntimeException e) {
t = e;
throw e;
} catch (Error e) {
t = e;
throw e;
} finally {
if (!threadDone) {
log.error(unexpectedDeathMessage, t);
}
}
}

processChildren方法

protected void processChildren(Container container, ClassLoader cl) {
try {
if (container.getLoader() != null) {
Thread.currentThread().setContextClassLoader
(container.getLoader().getClassLoader());
}
container.backgroundProcess();
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
log.error("Exception invoking periodic operation: ", t);
} finally {
Thread.currentThread().setContextClassLoader(cl);
}
//获取所有的子容器,递归调用
Container[] children = container.findChildren();
for (int i = 0; i < children.length; i++) {
if (children[i].getBackgroundProcessorDelay() <= 0) {
processChildren(children[i], cl);
}
}
}

Tomcat学习笔记(十一)的更多相关文章

  1. python3.4学习笔记(十一) 列表、数组实例

    python3.4学习笔记(十一) 列表.数组实例 #python列表,数组类型要相同,python不需要指定数据类型,可以把各种类型打包进去#python列表可以包含整数,浮点数,字符串,对象#创建 ...

  2. Go语言学习笔记十一: 切片(slice)

    Go语言学习笔记十一: 切片(slice) 切片这个概念我是从python语言中学到的,当时感觉这个东西真的比较好用.不像java语言写起来就比较繁琐.不过我觉得未来java语法也会支持的. 定义切片 ...

  3. JavaScript权威设计--JavaScript函数(简要学习笔记十一)

    1.函数调用的四种方式 第三种:构造函数调用 如果构造函数调用在圆括号内包含一组实参列表,先计算这些实参表达式,然后传入函数内.这和函数调用和方法调用是一致的.但如果构造函数没有形参,JavaScri ...

  4. SharpGL学习笔记(十一) 光源创建的综合例子:光源参数可调节的测试场景

    灯光的测试例子:光源参数可以调节的测试场景 先看一下测试场景和效果. 场景中可以切换视图, 以方便观察三维体和灯光的位置.环境光,漫射光,镜面反射光都可以在四种颜色间切换. 灯光位置和摄像机位置(Lo ...

  5. java jvm学习笔记十一(访问控制器)

     欢迎装载请说明出处: http://blog.csdn.net/yfqnihao/article/details/8271665 这一节,我们要学习的是访问控制器,在阅读本节之前,如果没有前面几节的 ...

  6. Tomcat 学习笔记二

    学习一 java.bean.PropertyChangeListener用来监听bean类的属性值改变.当改变时同时执行对应事件.而且是线程安全的.tomcat用此reload的Boolean值改变是 ...

  7. Tomcat ----> 学习笔记

    源码之几个常见类和接口的关系 在学习Servlet的时候经常见到以下几个合成单词和非合成单词:Servlet.GenericServlet.HttpServlet.它们之间有联系的.接下来我把它们的联 ...

  8. Tomcat学习笔记【1】--- WEB服务器、JavaEE、Tomcat背景、Tomcat版本

    本文主要讲学习Tomcat需要知道的基础知识. 一 Web服务器 1.1 简介 Web服务器可以解析HTTP协议.当Web服务器接收到一个HTTP请求,会返回一个HTTP响应,例如送回一个HTML页面 ...

  9. Oracle学习笔记十一 游标

    游标的简介 游标的概念 游标是从数据表中提取出来的数据,以临时表的形式存放在内存中,在游标中有一个数据指针,在初始状态下指向的是首记录,利用fetch语句可以移动该指针,从而对游标中的数据进行各种操作 ...

随机推荐

  1. 谈谈对bug的一点想法,说说做好日志记录的重要性

    说起程序猿,总绕不开的一个话题就是bug,估计每个程序猿听到某某测试跑过来一脸淫笑的告诉你这个功能有个bug的时候,总有种恨不得掐死他的想法.其实程序猿跟bug的关系,感觉有点像父亲和儿子的关系,自己 ...

  2. java经常看见 jdk5 jdk1.5 —— jdk6 jdk1.6 这两者有什么区别吗?

    问.java经常看见 jdk5 jdk1.5 —— jdk6 jdk1.6 这两者有什么区别吗? 答:没有区别,jdk5 和 jdk1.5 所代表的意思是一样的,只是叫法不一样 关键字: jdk5 j ...

  3. cx_freeze的安装使用

    python是一个非常非常优秀的编程语言,它最大的特性就是跨平台.python程序几乎可以在所有常见的平台中进行使用,而且大部分无需修改任何代码!不过,python也有一点点小缺憾(这个是由于自身本质 ...

  4. 英文缩写SFR

    英文缩写为SFR,是Special Function Register(特殊功能寄存器)的缩写.

  5. HTTP 响应时发生错误。这可能是由于服务终结点绑定未使用 HTTP 协议造成的。这还可能是由于服务器中止了 HTTP 请求上下文(可能由于服务关闭)所致。

    第一种:无法序列化 DataTable.未设置 DataTable 名称. 第二种: 排除过程如下: 1.用WCF调试状态下的客户端调用ESB的Publish方法调用成功,证明ESB的推送是没有问题的 ...

  6. C语言数组篇(一)一维数组

       0.  数组的两种表现形式         一种是常见的a[10];         //初学者常用         另一种是用指针表示的数组.   //实际工程使用.常用于参数传递       ...

  7. [Hdu4825]Xor Sum(01字典树)

    Description Zeus 和 Prometheus 做了一个游戏,Prometheus 给 Zeus 一个集合,集合中包含了N个正整数,随后 Prometheus 将向 Zeus 发起M次询问 ...

  8. JavaSE——javac、javap、jad

    一.javac 用法:javac <选项> <源文件> 其中,可能的选项包括: -help                            帮助信息   -g       ...

  9. .Net导出Word和Excel

    using System; using System.Collections.Generic; using System.Linq; using System.Web; public class Ex ...

  10. shell之echo and printf

    #!/bin/sh _________echo___________#read name #echo "$name It is a test" #read命令从标准的输入中读取一行 ...