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

10.容器

 
阅读更多

 

容器是一个处理用户servlet请求并返回对象给web用户的模块。
org.apache.catalina.Container接口定义了容器的形式,有四种容器:Engine(引擎), Host(主机), Context(上下文), 和 Wrapper(包装器)。
容器接口
一个容器必须实现org.apache.catalina.Container接口
传递一个Container实例给Connector对象的setContainer方法,然后Connector对象就可以使用container的invoke方法
HttpConnector connector = new HttpConnector();
SimpleContainer container = new SimpleContainer();
connector.setContainer(container);
对于Catalina的容器首先需要注意的是它一共有四种不同的容器:
Engine:表示整个Catalina的servlet引擎
Host:表示一个拥有数个上下文的虚拟主机
Context:表示一个Web应用,一个context包含一个或多个wrapper
Wrapper:表示一个独立的servlet
每一个概念之上是用org.apache.catalina包来表示的。
Engine、Host、Context和Wrapper接口都实现了Container即可。
它们的标准实现是StandardEngine, StandardHost, StandardContext, and StandardWrapper,它们都是org.apache.catalina.core包的一部分。

 



 


一个Catalina功能部署不一定需要所有的四种类型的容器。例如本章的第一个应用程序仅仅包括一个wrapper,而第二个应用程序是一个包含Context和wrapper的容器模块。
一个容器可以有一个或多个低层次上的子容器。例如,一个Context有一个或多个wrapper,而wrapper作为容器层次中的最底层,不能包含子容器。
Container接口被设计成Tomcat管理员可以通过server.xml文件配置来决定其工作方式的模式

Pipelining Tasks(流水线任务)
一个pipeline包含了改容器要唤醒的所有任务。每一个阀门表示了一个特定的任务。一个容器的流水线有一个基本的阀门,但是你可以添加任意你想要添加的阀门。
阀门的数目定义为添加的阀门的个数(不包括基本阀门)。有趣的是,阀门可以通过编辑Tomcat的配置文件server.xml来动态的添加。

理解了servlet过滤器,那么流水线和它的阀门的工作方式不难想象。
一个流水线就像一个过滤链,每一个阀门像一个过滤器。跟过滤器一样,一个阀门可以操作传递给它的request和response方法。
让一个阀门完成了处理,则进一步处理流水线中的下一个阀门,基本阀门总是在最后才被调用。

一个容器可以有一个流水线。当容器的invoke方法被调用的时候,容器将会处理流水线中的阀门,并一个接一个的处理,直到所有的阀门都被处理完毕
流水线的invoke方法的伪代码如下所示
// invoke each valve added to the pipeline
for (int n=0; n<valves.length; n++) {
 valve[n].invoke( ... );
}
// then, invoke the basic valve
basicValve.invoke( ... );

 

Tomcat的设计者选择了一种通过org.apache.catalina.ValveContext定义的方式来处理,这里介绍它如何工作的:
容器的invoke方法在被connector调用的时候所作的工作不难进行编码。容器调用的是流水线的invoke方法。
流水线接口的invoke方法前面跟容器接口的invoke方法签名相同
public void invoke(Request request, Response response) throws IOException, ServletException;
这里是Container接口中invoke方法在org.apache.catalina.core.ContainerBase的实现:
public void invoke(Request request, Response response)throws IOException, ServletException {
 pipeline.invoke(request, response);
}
Pipeline是容器中Pipeline接口的一个实例。
流水线必须保证说要添加给它的阀门必须被调用一次,流水线通过创建一个ValveContext接口的实例来实现它。
ValveContext是流水线的的内部类,这样ValveContext就可以访问流水线中所有的成员。ValveContext中最重要的方法是invokeNext方法
public void invokeNext(Request request, Response response) throws IOException, ServletException
在创建一个ValveContext实例之后,流水线调用ValveContext的invokeNext方法。ValveContext会先唤醒流水线的第一个阀门,然后第一个阀门会在完成它的任务之前唤醒下一个阀门。
ValveContext将它自己传递给每一个阀门,那么该阀门就可以调用ValveContext的invokeNext方法。Valve接口的invoke签名如下:
public void invoke(Request request, Response response, ValveContext ValveContext) throws IOException, ServletException

public void invoke(Request request, Response response, ValveContext valveContext) throws IOException, ServletException {
 // Pass the request and response on to the next valve in our pipeline
 valveContext.invokeNext(request, response);
 // now perform what this valve is supposed to do ...
}

org.apache.catalina.core.StandardPipeline类是容器流水线的实现
InvokeNext方法使用下标(subscript)和级别(stage)记住哪个阀门被唤醒。当第一次唤醒的时候,下标的值是0,级的值是1。
以你次,第一个阀门被唤醒,流水线的阀门获得ValveContext实例调用它的invokeNext方法。这时下标的值是1所以下一个阀门被唤醒,然后一步步的进行。

The Pipeline Interface流水线接口
我们提到的流水线的第一个方法是它的Pipeline接口的invoke方法,该方法会开始唤醒流水线的阀门。流水线接口允许你添加一个新的阀门或者删除一个阀门。
最后,可以使用setBasic方法来分配一个基本阀门给流水线,getBasic方法会得到基本阀门。最后被唤醒的基本阀门,负责处理request和回复response。
public interface Pipeline {
 public Valve getBasic();
 public void setBasic(Valve valve);
  public void addValve(Valve valve);
 public Valve[] getValves();
 public void invoke(Request request, Response response) throws IOException, ServletException;
 public void removeValve(Valve valve);
}

The Valve Interface阀门接口
阀门接口表示一个阀门,该组件负责处理请求。该接口有两个方法,invoke和getInfo方法。
Invoke方法如上所述,getInfo方法返回阀门的信息
public interface Valve {
 public String getInfo();
 public void invoke(Request request, Response response, ValveContext context) throws IOException, ServletException;
}

The ValveContext Interface阀门上下文接口
阀门上下文接口有两个方法,invokeNext方法如上所述,getInfo方法会返回阀门上下文的信息。ValveContext接口如下:
public interface ValveContext {
 public String getInfo();
 public void invokeNext(Request request, Response response)throws IOException, ServletException;
}


The Contained Interface Contained接口
一个阀门可以选择性的实现org.apache.catalina.Contained接口。该接口定义了其实现类跟一个容器相关联
public interface Contained {
 public Container getContainer();
 public void setContainer(Container container);
}

the Wrapper Interface Wrapper接口
org.apache.catalina.Wrapper接口表示了一个包装器。一个包装器是表示一个独立servlet定义的容器。
包装器继承了Container接口,并且添加了几个方法。包装器的实现类负责管理其下层servlet的生命中期,包括servlet的init,service,和destroy方法。
由于包装器是最底层的容器,所以不可以将子容器添加给它。如果addChild方法被调用的时候会产生IllegalArgumantException异常。
包装器接口中重要方法有allocate和load方法。allocate方法负责定位该包装器表示的servlet的实例
Load方法负责load和初始化servlet的实例

The Context Interface上下文(Context)接口
一个context在容器中表示一个web应用。一个context通常含有一个或多个包装器作为其子容器。
重要的方法包括addWrapper, createWrapper等方法

The Wrapper Application(包装器应用程序)
这个应用程序展示了如何写一个简单的容器模型
核心类是SimpleWrapper,它实现了Wrapper接口。SimpleWrapper类包括一个Pipeline和一个Loader类来加载一个servlet。
流水线包括一个基本阀门SimpleWrapperValve和两个另外的阀门ClientIPLoggerValve,HeaderLoggerValve)

 



 

public static void main(String[] args) {
		
		/**
		 * 初始化连接器
		 */
		HttpConnector connector = new HttpConnector();
		
		//创建一个包装器
		Wrapper wrapper = new SimpleWrapper();
		//告诉包装器要加载类的名字
		wrapper.setServletClass("ModernServlet");
		//创建了加载器
		Loader loader = new SimpleLoader(); 
		//两个阀门
		Valve valve1 = new HeaderLoggerValve(); 
		Valve valve2 = new ClientIPLoggerValve();
		//把加载器给包装器
		wrapper.setLoader(loader);
		//流水线添加俩个阀门
		((Pipeline) wrapper).addValve(valve1);
		((Pipeline) wrapper).addValve(valve2);
		//连接器设置容器
		//把包装器当做容器添加到连接器中,然后初始化并启动连接器
		connector.setContainer(wrapper);
		
		try{
			//连接器初始化,实现Lifecycle周期接口
			connector.initialize();
			//启动
			connector.start();
			System.in.read();
		}catch(Exception e){
			e.printStackTrace();
		}
	}

 

SimpleWrapper

package com.tomcat.core;

import java.beans.PropertyChangeListener;
import java.io.IOException;

import javax.naming.directory.DirContext;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
import javax.servlet.UnavailableException;

import org.apache.catalina.AccessLog;
import org.apache.catalina.Cluster;
import org.apache.catalina.Container;
import org.apache.catalina.ContainerListener;
import org.apache.catalina.InstanceListener;
import org.apache.catalina.Loader;
import org.apache.catalina.Manager;
import org.apache.catalina.Pipeline;
import org.apache.catalina.Realm;
import org.apache.catalina.Wrapper;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;

/**
 * 代表一个容器
 * @author Administrator
 *
 */
public class SimpleWrapper implements Wrapper {
	
	/**
	 * loader变量用于加载一个servlet类
	 */
	private Loader loader; 
	/**
	 * Parent变量表示该包装器的父容器
	 */
	protected Container parent = null;
	
	/**
	 * getLoader方法用于返回一个Loader对象用于加载一个servlet类。
	 * 如果一个包装器跟一个加载器相关联,会返回该加载器。
	 * 否则返回其父容器的加载器,如果没有父容器,则返回null。
	 */
	public Loader getLoader() {
		if(loader!=null)
			return loader;
		if(parent!=null)
			return parent.getLoader();
		return null;
	}

	public void addInitParameter(String arg0, String arg1) {
		// TODO Auto-generated method stub

	}

	public void addInstanceListener(InstanceListener arg0) {
		// TODO Auto-generated method stub

	}

                .......

}

 

SimpleLoader

 

package com.tomcat.core;

import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLStreamHandler;

import org.apache.catalina.Container;
import org.apache.catalina.Loader;

/**
 * 容器中加载servlet的任务被分配给了Loader实现
 * impleLoader就是一个Loader实现。
 * 它知道如何定位一个servlet,并且通过getClassLoader获得一个java.lang.ClassLoader实例用来查找servlet类位置
 * @author Administrator
 *
 */
public class SimpleLoader implements Loader {

	////////WEB_ROOT用来指明在哪里查找servlet类
	public static final String WEB_ROOT = System.getProperty("user.dir") + File.separator + "webroot";
	
	ClassLoader classLoader = null; 
	Container container = null;
	
	/**
	 * 初始化类加载器
	 */
	public SimpleLoader(){
		try {
			URL[] urls = new URL[1];
			URLStreamHandler streamHandler = null;
			File classPath = new File(WEB_ROOT);
			String repository = (new URL("file", null, classPath.getCanonicalPath() + File.separator)).toString() ;
			urls[0] = new URL(null, repository, streamHandler);
			classLoader = new URLClassLoader(urls);
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public void addPropertyChangeListener(PropertyChangeListener arg0) {
		// TODO Auto-generated method stub
		
	}

	......................


}

 

HeaderLoggerValve

 

 

package com.tomcat.core;

import java.io.IOException;

import javax.servlet.ServletException;

import org.apache.catalina.CometEvent;
import org.apache.catalina.Contained;
import org.apache.catalina.Container;
import org.apache.catalina.Valve;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;

/**
 * 是一个阀门
 * 打印请求头部到控制台上
 * @author Administrator
 *
 */
public class HeaderLoggerValve implements Valve, Contained {

	public void backgroundProcess() {
		// TODO Auto-generated method stub

	}

	public void event(Request arg0, Response arg1, CometEvent arg2)
			throws IOException, ServletException {
		// TODO Auto-generated method stub

	}

	public String getInfo() {
		// TODO Auto-generated method stub
		return null;
	}

	public Valve getNext() {
		// TODO Auto-generated method stub
		return null;
	}

	public void invoke(Request arg0, Response arg1) throws IOException,
			ServletException {
		// TODO Auto-generated method stub

	}

	...................

}

 

ClientIPLoggerValve

 

package com.tomcat.core;

import java.io.IOException;

import javax.servlet.ServletException;

import org.apache.catalina.CometEvent;
import org.apache.catalina.Contained;
import org.apache.catalina.Container;
import org.apache.catalina.Valve;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;

/**
 * ClientIPLoggerValve是一个阀门,它打印出客户端的IP地址到控制台
 * @author Administrator
 *
 */
public class ClientIPLoggerValve implements Valve,Contained{

	protected Container container;
	
	................................

	

}

 

 

SimplePipeline

package com.tomcat.core;

import org.apache.catalina.Pipeline;
import org.apache.catalina.Valve;

/**
 * 流水线
 * @author Administrator
 *
 */
public class SimplePipeline implements Pipeline {

	public void addValve(Valve arg0) {
		// TODO Auto-generated method stub

	}

	public Valve getBasic() {
		// TODO Auto-generated method stub
		return null;
	}

	public Valve getFirst() {
		// TODO Auto-generated method stub
		return null;
	}

	public Valve[] getValves() {
		// TODO Auto-generated method stub
		return null;
	}

	public void removeValve(Valve arg0) {
		// TODO Auto-generated method stub

	}

	public void setBasic(Valve arg0) {
		// TODO Auto-generated method stub

	}

}

 

 

 

一个仅仅包括一个包装器的简单的web应用。该程序仅仅包括一个servlet
大多数的网络应用需要多个servlet。在这些应用中,需要一个跟包装器不同的容器:上下文。
如何使用一个包含两个包装器的上下文来包装两个servlet类。
当有多于一个得包装器的时候,需要一个map来处理这些子容器,对于特殊的请求可以使用特殊的子容器来处理。

在这个程序中,mapper是SimpleContextMapper类的一个实例,
它继承了Tomcat 4中的org.apache.catalina.Mapper接口。一个容器也可以有多个mapper来支持多协议。
例如容器可以用一个mapper来支持HTTP协议,而使用另一个mapper来支持HTTPS协议

public interface Mapper {
 public Container getContainer();
 public void setContainer(Container container);
 public String getProtocol(); public void setProtocol(String protocol);
 public Container map(Request request, boolean update);
}
getContainer返回该容器的mapper,
setContainer方法用于联系一个容器到mapper。
 getProtocol返回该mapper负责处理的协议,
setProtocol用于分配该容器要处理的协议。
map方法返回处理一个特殊请求的子容器。

 



 

 

 

SimpleContext表示一个上下文,它使用SimpleContextMapper作为它的mapper,SimpleContextValve作为它的基本阀门。
该上下文包括两个阀门ClientIPLoggerValve和HeaderLoggerValve。
用SimpleWrapper表示的两个包装器作为该上下文的子容器被添加。
包装器吧SimpleWrapperValve作为它的基本阀门,但是没有其它的阀门了。
该上下文应用程序使用同一个加载器、两个阀门。但是加载器和阀门时跟该上下文关联的,而不是跟包装器关联。
这样,两个加载器就可以都使用该加载器。该上下文被当做连接器的容器

基本流程如下
1. 一个容器有一个流水线,容器的invoke方法会调用流水线的invoke方法。
2. 流水线的invoke方法会调用添加到容器中的阀门的invoke方法,然后调用基本阀门的invoke方法。
3. 在一个包装器中,基本阀门负责加载相关的servlet类并对请求作出相应。
4. 在一个有子容器的上下文中,基本法门使用mapper来查找负责处理请求的子容器。如果一个子容器被找到,子容器的invoke方法会被调用,然后返回步骤1。

 

package com.tomcat.startup;

import org.apache.catalina.Context;
import org.apache.catalina.Loader;
import org.apache.catalina.Pipeline;
import org.apache.catalina.Valve;
import org.apache.catalina.Wrapper;

import com.tomcat.core.ClientIPLoggerValve;
import com.tomcat.core.HeaderLoggerValve;
import com.tomcat.core.HttpConnector;
import com.tomcat.core.Mapper;
import com.tomcat.core.SimpleContext;
import com.tomcat.core.SimpleContextMapper;
import com.tomcat.core.SimpleLoader;
import com.tomcat.core.SimpleWrapper;

public final class Bootstrap2 {

	/**
	 * @param args
	 */
	public static void main(String[] args) {

		HttpConnector connector = new HttpConnector();
	    Wrapper wrapper1 = new SimpleWrapper();
	    wrapper1.setName("Primitive");
	    wrapper1.setServletClass("PrimitiveServlet");
	    Wrapper wrapper2 = new SimpleWrapper();
	    wrapper2.setName("Modern");
	    wrapper2.setServletClass("ModernServlet");

	    Context context = new SimpleContext();
	    context.addChild(wrapper1);
	    context.addChild(wrapper2);

	    Valve valve1 = new HeaderLoggerValve();
	    Valve valve2 = new ClientIPLoggerValve();

	    ((Pipeline) context).addValve(valve1);
	    ((Pipeline) context).addValve(valve2);

	    Mapper mapper = new SimpleContextMapper();
	    mapper.setProtocol("http");
	    context.addMapper(mapper);
	    Loader loader = new SimpleLoader();
	    context.setLoader(loader);
	    // context.addServletMapping(pattern, name);
	    context.addServletMapping("/Primitive", "Primitive");
	    context.addServletMapping("/Modern", "Modern");
	    connector.setContainer(context);
	    try {
	      connector.initialize();
	      connector.start();

	      // make the application wait until we press a key.
	      System.in.read();
	    }
	    catch (Exception e) {
	      e.printStackTrace();
	    }
	  }
	}

}

 

  • 大小: 191.6 KB
  • 大小: 142.7 KB
  • 大小: 191.4 KB
分享到:
评论

相关推荐

    2.容器技术与应用_Docker.pptx

    10.分布式系统设计实战.pptx 11.系统实战需求物料.pptx 另还有企培专家课程:设计理念和开发,面向企业架构师和中层管理人员,详细描述了IT技术管理、敏捷开发流程、DDD实践、部门管理等内容。 更多,深度学习、...

    Prometheus容器监控架构.docx

    Prometheus容器监控架构 ...10.容器监控:Prometheus容器监控架构鼓励在堆栈的每一层都采用高度详细的度量工具,容器的状态,通过的请求流,甚至是运行于其中的应用的深层信息都通过度量工具对外可见。

    2009年压力容器设计考核参考试题.pdf

    10. 容器的分级:按照设计压力大小,《容规》将压力容器划分为低压、中压、高压和超高压四级。对于易燃或毒性程度为中度危害介质的中压储存容器和反应容器,其PV乘积也会影响容器的分类。 11. 排放能力:安全阀和...

    压力容器设计人员考试试题.docx

    10. 容器分类:根据设计压力和工作压力,以及直径和长度,可以确定氧气储罐属于哪一类压力容器。 11. 判断题涉及的法规和规定:例如,特种设备安全监察条例的实施日期,以及多腔压力容器的设计和制造要求,这些都是...

    10.洁净区容器具清洁消毒标准操作规程[定稿].pdf

    10.洁净区容器具清洁消毒标准操作规程[定稿].pdf

    Docker容器详解.docx

    3.2. docker exec 命令 10 3.3. docker commit 命令 11 3.4. docker build 命令 12 3.5. docker-compose 命令 13 4. Docker 容器使用 16 4.1. 查看所有的容器 16 4.2. 查看运行中的容器 16 4.3. 查看容器日志...

    AAS-V10.zip

    - **容器**:如Servlet容器和EJB容器,负责管理Java组件的生命周期和资源。 - **集群**:多个Apusic服务器可以组成一个集群,实现负载均衡和故障转移。 - **热部署**:允许在不中断服务的情况下更新应用程序。 - **...

    10个精选的容器应用案例

    描述:“10个精选的容器应用案例10个精选的容器应用案例10个精选的容器应用案例” 标签:“容器应用” 知识点: 1. 容器技术的发展与应用:自2013年Docker诞生以来,容器技术在业界迅速受到追捧,特别是在企业级...

    STL容器(一)(附件STL帮助手册)

    10. 容器适配器:stack、queue和priority_queue是容器适配器,它们基于底层的容器(通常是vector或deque)提供栈、队列和优先级队列的行为。 11. 泛型编程:STL的一个核心特性是泛型编程,这意味着所有容器和算法都...

    八年级物理液体压强计算题.doc

    10. 容器对桌面的压强:考虑容器底面积和容器与液体的总重力,计算容器对桌面的压强。 11. 湖水对堤坝底部的压强:湖水深度直接决定了压强大小,计算方法同上。 12. 弯管内的液体压强:即使管子形状改变,液体在...

    018bkjhs3asa_C++_

    10. 容器的内存管理: 容器会自动管理内部对象的内存,但开发者需要了解内存分配和释放可能带来的性能影响,例如使用reserve方法预先分配空间以减少内存碎片。 在实际编程中,理解并熟练运用这些容器和操作,可以...

    容器技术之PPT教案.pptx

    10. perf_event:增加了对每 group 的监测跟踪的能力。 Linux 容器虚拟技术(LXC)是指通过虚拟化操作系统的方式来管理代码和应用程序,实现轻量级虚拟化和资源isolated 分组。 容器技术之 Docker 是指使用 Docker...

    关于运输和储存容器的介绍说明.rar

    本文件“运输和储存容器.pdf”可能涵盖了以下多个方面的重要知识点: 1. 容器种类:运输和储存容器有多种类型,如金属箱、塑料桶、木质托盘、集装箱、周转箱等。每种类型的容器都有其特定的适用场景和优缺点,例如...

    Java 图形用户界面编程实验源码集锦.rar

    10.标准GUI组件(下拉列表)。  11.标准GUI组件(列表)。12.标准GUI组件(滚动条)。13.鼠标事件。14.键盘事件。  15.菜单(下拉菜单)。16.菜单(多级菜单)。17.菜单(弹出式菜单)。18.对话框。  相信这些Jaa...

    VFP考试试题及答案终稿.pdf

    10. 容器类对象:页框(PageFrame)是容器类对象,可以包含其他控件,选项C正确。 11. 自由表索引:自由表不能创建主索引,选项A正确。 12. 继承性:继承性体现了面向对象编程的共享机制,允许子类继承父类的属性...

    容器教程培训视频.zip

    10 docker版本介绍mp4 11docker部署YUM源获取mp4 12 docker安装及服务启动,mp4 13容器镜像获取mp4 14运行个容器mp4 15 dockerdaemon配置远程及本地管理mp4 16 dockel命令行命令介绍.mp4 17docker获取镜像mp4 18...

    压力容器表格2.pdf

    10. 筒节(短节)检查记录 筒节(短节)检查记录是用于记录和管理压力容器制造过程中的筒节(短节)检查情况的记录。该记录用于跟踪和记录压力容器制造过程中的筒节(短节)检查情况,以确保压力容器的制造符合相关...

    八年级物理全册第八章压强第二节科学探究液体的压强作业设计新版沪科版2020030721

    10. 容器底部受到的压力与压强:对于高度相等、底面积相等的容器,如果装有同种液体,尽管液体体积相同,但由于容器形状可能不同,液体深度可能会不同,因此容器底部的压强和压力可能也会有所不同。 11. 海水深潜...

    高一实验班专题影响化学平衡移动的因素[精选].doc

    10. 容器类型与平衡:恒压容器中,如果加入惰性气体,总压强不变,平衡不移动;恒容容器中,加入惰性气体,各组分的分压不变,平衡也不移动。 11. 固体对平衡的影响:固体对平衡移动无直接影响,因为其浓度视为常数...

    c++标准库stl帮助文档

    10. 容器适配器:除了基本的容器外,STL还提供了一些适配器,如优先级队列(priority_queue)、反向列表(deque)等,它们是对现有容器功能的扩展。 《C++标准库》帮助文档是学习STL的重要资源,它详尽地介绍了每个...

Global site tag (gtag.js) - Google Analytics