`
韩悠悠
  • 浏览: 842500 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

17,tomcat中StandardContext

 
阅读更多

一个上下文容器(Context)代表一个web应用,每一个上下文包括多个包装器(Wrapper),每个包装器代表一个Servlet
上下文还需要其它的一些组件如加载器和管理器
Context接口的标准实现,org.apache.catalina.core.StandardContext类

StandardContext配置
创建一个StandardContext实例之后,必须调用它的start方法,这样它就能为受到的HTTP请求服务了。一个StandardContext对象可能启动失败,
这时候属性available被设置为false,属性available表示了StandardContext对象的可用性。
在一个Tomcat部署中,StandardContext的配置过程做了以下事情:准备读取和解析%CATALINA_HOME%/conf 目录下面的web.xml,
部署所有应用程序,确保StandardContext实例可以处理应用级别的web.xml。
另外,配置需要添加一个验证器阀门和证书阀门(authenticator valve and a certificate valve)
StandardContext的属性之一是它属性configured,用来表示该StandardContext是否已经配置了
StandardContext使用一个事件监听器来作为它的配置器
当StandardContext实例的start方法被调用的时候,首先触发一个生命周期事件
。该事件唤醒一个监听器来配置该StandardContext实例。配置成功后,该监听器将configured属性设置为true。
否则,StandardContext对象拒绝启动,这样就不能对HTTP请求进行服务了。

StandardContext构造函数
public StandardContext() {
 super();
 pipeline.setBasic(new StandardContextValve());
 namingResources.setContainer(this);
}
在构造函数中,最重要的事情是在StandardContext的流水线上添加了一个类型为StandardContextValve的基本阀门

 


启动StandardContext
Start方法初始化StandardContext对象并让生命周期监听器配置该StandardContext实例。如果配置成功,
生命周期监听器会将configured属性设置为true。最后start方法,将available属性设置为true或者false。
如果是true的话表示该StandardContext属性配置完毕并且所有相关子容器和组件已经成功启动,
这样就能对HTTP请求进行服务了,如果是false则表示出现了错误。

public synchronized void start() throws LifecycleException {
	if (started)
		throw new LifecycleException (sm.getString("containerBase.alreadyStarted", logName()));
	lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);
	setAvailable(false);
	setConfigured(false);
	boolean ok = true;
	if (getResources() == null) {
		try {
			if ((docBase != null) && (docBase.endsWith(".war"))) 
				setResources(new WARDirContext());
			else 
				setResources(new FileDirContext());
		}catch (IllegalArgumentException e) {
			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) {
		if (getPrivileged()) {
			setLoader(new WebappLoader(this.getClass().getClassLoader()));
		}else{
			setLoader(new WebappLoader(getParentClassLoader()));
		}
	}
	if (getManager() == null) {
		setManager(new StandardManager());
	}
	// Initialize character set mapper 
	getCharsetMapper();
	// Post work directory 
	postWorkDirectory();
	String useNamingProperty = 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);
		}
	}
	ClassLoader oldCCL = bindThread();
	if (ok) {
		try { 
			addDefaultMapper(this.mapperClass); 
			started = true;
			if ((loader != null) && (loader instanceof Lifecycle)) 
				((Lifecycle) loader).start();
			if ((logger != null) && (logger instanceof Lifecycle))
				((Lifecycle) logger).start();
			// Unbinding thread
			unbindThread(oldCCL);
			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();
			
			Mapper mappers[] = findMappers();
			for (int i = 0; i < mappers.length; i++) {
				if (mappers[i] instanceof Lifecycle) 
					((Lifecycle) mappers[i]).start();
			}
			Container children[] = findChildren();
			for (int i = 0; i < children.length; i++) {
				if (children[i] instanceof Lifecycle)
					((Lifecycle) children[i]).start();
			}
			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);
		}
	}
	if (!getConfigured())
		ok = false;
	if (ok) 
		getServletContext().setAttribute (Globals.RESOURCES_ATTR, getResources());
	if (ok) {
		postWelcomeFiles();
	}
	if (ok) { 
		if (!listenerStart())
			ok = false;
	}
	if (ok) {
		if (!filterStart()) 
			ok = false;
	}
	// Load and initialize all "load on startup" servlets 
	if (ok) 
		loadOnStartup(findChildren());
	unbindThread(oldCCL);
	if (ok){
		setAvailable(true);
	}else{
		stop();
		setAvailable(false);
	}
	lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
}

 

 

下面是该方法做的事情:
· 触发BEFORE_START事件
· 设置availability属性为false
· 设置configured属性为false
· 设置源(resources)
· 设置加载器
· 设置管理器
· 初始化属性map
· 启动跟该上下文相关的组件
· 启动子容器(包装器)
· 启动流水线
· 启动管理器
· 触发START事件
。监听器(ContextConfig)会进行一系列配置操作,配置成功后,将StandardContext实例的configured属性设置为true。
· 检查configured属性的值,如果为true:调用postWelcomPages方法,加载子包装器,并将available属性设置为true。
 如果configured属性为false调用stop方法
· 触发AFTER_START事件

 

Invoke方法
StandardContext's方法由相关联的连接器调用,
如果该上下文是一个主机(host)的子容器,
有该主机的invoke方法调用。StandardContext的invoke方法首先检查是否正在重加载该应用程序,
是的话,等待知道加载完毕。然后调用它的父类ContainerBase的invoke方法

public void invoke(Request request, Response response){
	while (getPaused()) {
		try {
			Thread.sleep(1000); 
		} catch (InterruptedException e) { ; }
	}
	if (swallowOutput) { 
		try {
			SystemLogHandler.startCapture();
			super.invoke(request, response);
		}
	}else { 
		super.invoke(request, response); 
	}
}

 

 

方法getPaused获得属性paused的值,当应用程序正在加载的时候该属性为ture。


StandardContextMapper
对于每一个请求,invoke方法都会调用StandarContext流水线基本阀门的invoke方法。
StandarContext的基本阀门用org.apache.catalina.core.StandardContextValve类表示。
StandardContextValve实例查找包含它的StandardContext。StandardContextValve使用上下文容器的map来查找合适的包装器
StandardContext的父类ContainerBase定义了addDefaultMapper方法来添加

protected void addDefaultMapper(String mapperClass) {
	if (mapperClass == null) 
		return;
	if (mappers.size() >= 1)
		return;
	try { 
		Class clazz = Class.forName(mapperClass);
		Mapper mapper = (Mapper) clazz.newInstance();
		mapper.setProtocol("http"); 
		addMapper(mapper);
	} catch (Exception e) {}
}

 

 

重加载支持
StandardContext定义了reloadable属性来标识是否支持应用程序的重加载。
当允许重加载的时候,当web.xml或者WEB-INF/classes目录下的文件被改变的时候会重加载。
StandardContext 中Loader接口的标准实现WebappLoader类,有一个单独线程来检查WEB-INF目录下面所有类和JAR文件的时间戳
你需要做的是启动该线程,将 WebappLoader关联到StandardContext,使用setContainer方法即可

public void setContainer(Container container) {
	if ((this.container != null) && (this.container instanceof Context)) 
		((Context) this.container).removePropertyChangeListener(this);
	Container oldContainer = this.container;
	this.container = container;
	support.firePropertyChange("container", oldContainer, this.container);
	// Register with the new Container (if any) 
	if ((this.container!=null) && (this.container instanceof Context)) {
		setReloadable( ((Context) this.container).getReloadable() ); 
		((Context) this.container).addPropertyChangeListener(this); 
	}
}

 

 


注意最后一个if语句块中,如果容器是一个上下文容器,调用setReloadable方法,
也就是说WebappLoader的reloadable属性跟StandardContext的reloadable属性相同。
下面是WebappLoader对setReload方法的实现:

 

public void setReloadable(boolean reloadable) {
	boolean oldReloadable = this.reloadable;
	this.reloadable = reloadable;
	support.firePropertyChange("reloadable", new Boolean(oldReloadable), new Boolean(this.reloadable));
	if (!started)
		return;
	if (!oldReloadable && this.reloadable)
		threadStart();
	else if (oldReloadable && !this.reloadable)
		threadStop();
	}
}

 

如果将reloadable属性设置为true,调用threadStart方法。如果从true到false,则调用threadStop方法。
threadStart方法启动一个线程持续的检查WEB-INF目录下面的类文件和JAR文件的时间戳。threadStop方法用于停止该线程。
类的时间戳是由backgroundProcess方法调用

backgroundProcess方法
一个上下文容器需要其它组件如加载器和管理器的支持。这些组件通常需要一个单独的线程来处理后台过程(background processing)
所有的后台过程都分享同一个线程。如果一个组件或者是容器需要定期的来执行操作,
它需要做的是将这些代码写入到backgroundProcess方法即可。

 

protected void threadStart() {
	if (thread != null) 
		return;
	if (backgroundProcessorDelay <= 0)
		return;
	threadDone = false; 
	String threadName = "ContainerBackgroundProcessor[" + toString() + "]";
	thread = new Thread(new ContainerBackgroundProcessor(), threadName);
	thread.setDaemon(true); 
	thread.start();
}

 


方法threadStart传递一个ContainerBackgroundProcessor对象创建一个新线程。
ContainerBackgroundProcessor实现了java.lang.Runnable接口

protected class ContainerBackgroundProcessor implements Runnable {
	public void run() {
		while (!threadDone) {
			try {
				Thread.sleep(backgroundProcessorDelay * 1000L);
			} catch (InterruptedException e) { ; }
			if (!threadDone) {
				Container parent = (Container) getMappingObject();
				ClassLoader cl = Thread.currentThread().getContextClassLoader();
				if (parent.getLoader() != null) { 
					cl = parent.getLoader().getClassLoader(); 
				}
				processChildren(parent, cl);
			}
		}
	}

	protected void processChildren(Container container, ClassLoader cl) {
		try { 
			if (container.getLoader() != null) {
				Thread.currentThread().setContextClassLoader (container.getLoader().getClassLoader());
			}
			container.backgroundProcess();
		}catch (Throwable 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);
			}
		}
	}
}

 

ContainerBackgroundProcessor是ContainerBase的内部类,
在他的run方法里,有一个while循环定期的调用它的processChildren方法

分享到:
评论

相关推荐

    WEB服务器工作机制由浅至深(6):【How Tomcat Works】第12章StandardContext翻译分析

    StandardContext是Tomcat中的核心组件之一,它负责管理和维护一个Web应用程序。每个Web应用程序在Tomcat中都有一个对应的StandardContext实例,它管理着Web应用的上下文、类加载器、session配置、过滤器链等关键...

    Spring Boot启动过程(六)之内嵌Tomcat中StandardHost、StandardContext和StandardWrapper的启动教程详解

    Spring Boot启动过程(六)之内嵌Tomcat中StandardHost、StandardContext和StandardWrapper的启动教程详解 Spring Boot是一个基于Java的开源框架,用于快速开发Web应用程序。它提供了许多便捷的功能和配置,包括...

    嵌入tomcat

    嵌入Tomcat是一种将Apache Tomcat服务器直接集成到Java应用程序中的技术,这使得应用程序能够独立于传统的Web服务器环境运行,增强了应用的灵活性和可移植性。本文将深入探讨嵌入Tomcat的基本概念、优势以及其实现...

    tomcat6,7源码

    在源码中,可以看到Catalina如何通过`org.apache.catalina.core.StandardEngine`、`org.apache.catalina.core.StandardHost`和`org.apache.catalina.core.StandardContext`来管理Web应用程序的生命周期。理解这些类...

    我的tomcat7源码手撕过程

    2. **加载Classpath**:在启动脚本中,通过关键字`CLASSPATH`指定`bin\bootstrap.jar`等JAR包的位置,这些JAR包包含了启动Tomcat所需的类和资源。 3. **主类加载**:脚本中通过关键字`MAINCLASS`指定了主类`org....

    tomcat7.0.82 API 编程

    API编程在Tomcat中扮演着核心角色,允许开发者深入理解和操作Tomcat的各种功能。 一、Tomcat API简介 Tomcat的API提供了对服务器内部组件的访问,包括Servlet、JSP、连接器(Connector)、容器(Container)等。...

    深入剖析Tomcat源码

    《深入剖析Tomcat源码》是一本专注于解析Apache Tomcat服务器内部工作原理的书籍,而提供的压缩包文件正是这本书中的源代码示例。Tomcat作为一款广泛应用的开源Java Servlet容器,其源码对于理解Web应用服务器的工作...

    apache-tomcat-9.0.8-src源码资源

    Tomcat提供自动部署和管理Web应用的功能,这涉及到`StandardContext`和`LifeCycle`接口的实现。 6. **安全管理**: Tomcat的安全特性包括用户认证、角色授权等,这在`org.apache.catalina.security`和`org.apache...

    查看Tomcat源代码

    在IT行业中,深入理解Web服务器的内部工作原理是至关重要的,特别是对于Java开发者而言,Tomcat作为最常用的Servlet容器,其源代码的阅读能够帮助我们更好地优化应用性能、解决复杂问题以及理解HTTP协议的实现。...

    Tomcat8.0底层源码

    通过对Tomcat 8.0源码的学习,开发者能够更深入地理解Web服务器的工作机制,从而更好地优化应用性能,解决复杂问题,甚至参与到Tomcat的贡献和维护中。这是一条通往Java Web高级开发者之路的必经之路。

    TomCat API

    TomCat API允许开发者通过编程方式动态部署和卸载应用,例如使用`org.apache.catalina.core.StandardContext`类进行上下文配置。 3. **连接器(Connector)**:TomCat通过`Connector`组件与外界进行通信,接收和...

    tomcat-4.1.40-src

    在本文中,我们将深入探讨Tomcat 4.1.40的源代码,揭示其内部工作原理,帮助开发者更好地理解和优化他们的应用程序。 首先,Tomcat 4.1.40是Tomcat历史上的一个早期版本,发布于2004年,尽管现在最新的版本已经发展...

    S04-tomcat之Filter内存马1

    【描述】:"理解Tomcat中的Filter内存马,涉及servlet-api以及Tomcat组件动态注册的实现,关注Filter的生命周期和内存马的创建思路。" 在Java Web开发中,Tomcat作为常用的Servlet容器,其内部机制包括了对Filter的...

    《深入剖析Tomcat(中文版+英文版)》.rar

    《深入剖析Tomcat(中文版+英文版)》.rar 《深入剖析Tomcat》深入剖析Tomcat 4和Tomcat 5中的每个组件(如果TOMCAT...第17章 启动tomcat 第18章 部署器 第19章 manager应用程序的servlet类 第20章 基于jmx的管理

    tomcat源码学习之环境搭建

    接着,从描述中的链接下载Tomcat的源码,这里是Apache-tomcat-8.5.5。解压后,你会看到一个结构清晰的目录,包含多个子目录和文件,如`bin`、`conf`、`lib`、`webapps`等。`bin`目录包含启动和停止Tomcat的脚本,`...

    apache-tomcat-6.0.16.zip和源码

    Tomcat 6.0系列是一个较旧的版本,但它仍然是许多开发人员学习和测试环境中的常用选择,因为它轻量级且易于配置。 在"apache-tomcat-6.0.16.zip"中,你可以找到以下关键组成部分: 1. **bin**:包含启动和停止...

    Tomcat源码分析

    5. **Pipeline和Valve**: Tomcat的请求处理管道,Valve是管道中的处理单元,可以通过自定义Valve实现特定功能。 通过对Tomcat源码的分析,开发者可以更好地理解其工作原理,从而优化性能、解决运行问题,或者开发出...

    tomcat6.0 jar包及源代码

    在"apache-tomcat-6.0.16.zip"文件中,包含了Tomcat运行所需的各种jar包,如`catalina.jar`、`jasper.jar`、`servlet-api.jar`等。这些jar包分别承担了不同的功能:`catalina.jar`是Tomcat的主要执行引擎,负责...

Global site tag (gtag.js) - Google Analytics