赞
踩
Catalina的两个模板:连接器(connector)和容器(container)
连接器:负责将一个请求与容器相关联(为每一个接收到的Http请求创建一个request对象和一个response对象,然后将处理过程交给容器)
容器:从连接器中接收request对象和response对象,并负责调用响应的Servlet的service对象
连接服务器
- public class HttpConnector implements Runnable {
- boolean stopped;
- private String scheme = "http";
-
- @Override
- public void run() {
- ServerSocket serverSocket = null;
- int port = 8080;
- try {
- serverSocket = new ServerSocket(port, 1, InetAddress.getByName("127.0.0.1"));
- } catch (IOException e) {
- e.printStackTrace();
- System.exit(1);
- }
- while (!stopped) {
- Socket socket = null;
- try {
- socket = serverSocket.accept();
- } catch (IOException e) {
- e.printStackTrace();
- }
- HttpProcessor processor = new HttpProcessor(this);
- processor.process(socket);
- }
- }
-
- public void start() {
- Thread thread = new Thread(this);
- thread.start();
- }
- }

处理
- public class HttpProcessor {
- private HttpConnector httpConnector;
- private HttpRequest request;
- private HttpResponse response;
-
- public HttpProcessor(HttpConnector httpConnector) {
- this.httpConnector = httpConnector;
- }
-
- public void process(Socket socket) {
- SocketInputStream inputStream = null;
- OutputStream outputStream = null;
-
- try {
- inputStream = new SocketInputStream(socket.getInputStream(), 2048);
- outputStream = socket.getOutputStream();
- request = new HttpRequest(inputStream);
- response=new HttpResponse(outputStream);
- response.setRequest(request);
- response.setHeader("Server", "Jsq Servlet Container");
- parseRequest(inputStream, outputStream);
- parseHeader(inputStream);
- if (request.getRequestURI().startWith("/servlet/")) {
- ServletProcessor processor = new ServletProcessor();
- processor.process(request,response);
- }else{
- StaticResourceProcessor processor = new StaticResourceProcessor();
- processor.process(request, response);
- }
- socket.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- }
- }

处理请求servlet资源,并为Web客户端填充填充response对象
- HttpConnector connector = new HttpConnector();
- SimpleContainer container = new SimpleContainer();
- connector.setContainer(container);
Engine>Host>Context>Wrapper(包含关系)
4个接口:Pipeline(addValve方法添加阀)、Valve(阀,用来处理接收到的请求)、ValveContext(实现依次调用阀)、Contained(限制至多与一个servlet容器相关联)
一个servlet容器中有一条管道,当调用容器的invoke方法,容器会将处理工作交给管道处理,管道会从第一个阀开始,依次执行任务,知道所有任务执行完成为止(调用ValveContext实例的invokeNext方法)
一个Wrapper的实现
- public static void main(String[] args) {
- HttpConnector connector = new HttpConnector();
- SimpleWrapper wrapper = new SimpleWrapper();
- wrapper.setServletClass("ModernServlet");
- SimpleLoader loader = new SimpleLoader();
- HeaderLoggerValve headerLoggerValve = new HeaderLoggerValve();
- ClientIPLoggerValve clientIPLoggerValve = new ClientIPLoggerValve();
- wrapper.setLoader(loader);
- ((Pipeline) wrapper).addValve(headerLoggerValve);
- ((Pipeline) wrapper).addValve(clientIPLoggerValve);
- connector.setContainer(wrapper);
- try {
- connector.initialize();
- connector.start();
- System.in.read();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }

一个Context实现
- public static void main(String[] args) {
- HttpConnector connector = new HttpConnector();
-
- SimpleWrapper wrapper1 = new SimpleWrapper();
- wrapper1.setName("Modern");
- wrapper1.setServletClass("ModernServlet");
- SimpleWrapper wrapper2 = new SimpleWrapper();
- wrapper2.setName("Primitive");
- wrapper2.setServletClass("Primitive");
- SimpleContext context = new SimpleContext();
- context.addChild(wrapper1);
- context.addChild(wrapper2);
-
- HeaderLoggerValve headerLoggerValve = new HeaderLoggerValve();
- ClientIPLoggerValve clientIPLoggerValve = new ClientIPLoggerValve();
- context.setLoader(loader);
- ((Pipeline) context).addValve(headerLoggerValve);
- ((Pipeline) context).addValve(clientIPLoggerValve);
-
- SimpleContextMapper mapper = new SimpleContextMapper();
- mapper.setProtocol("http");
- context.addMapper(mapper);
-
- SimpleLoader loader = new SimpleLoader();
- context.setLoader(loader);
- context.addServletMapping("/Primitive","Primitive");
- context.addServletMapping("/Modern","Modern");
- connector.setContainer(context);
- try {
- connector.initialize();
- connector.start();
- System.in.read();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }

原理
容器中包含一个管道,容器的invoke方法会调用管道的invoke方法(如:SimpleContext类的invoke方法调用pipeline的invoke方法)
管道的invoke方法会调用所有添加到其容器中的阀,再调用其基础阀的invoke方法(pipeline的invoke方法调用pipelineValveContext的invokeNext,包含ContextValve的invoke方法)
在Wrapper实例中,基础阀负责载入相关联的servlet类,并对请求进行响应(ContextValve的invoke方法)
在包含子容器的Context实例中,基础阀使用映射器来查找一个子容器,该子容器负责处理接收到的请求,若找到相应的子容器,则调用器invoke方法,转到步骤1继续执行(ContextValve的invoke方法中,context.map(request,true),分配servlet实例,并调用它的service()方法)
context.map方法中
String name = context.findServletMapping(relativeURI) wrapper = (Wrapper) context.findChild(name)
start具体步骤
若一个Context实例使用ContextConfig对象进行设置,就必须使用一个Host对象,使用ContextConfig对象需要知道应用程序web.xml文件的位置,这里代码显示Context实例需要一个Host实例作为其父容器
- StandardHost host = new StandardHost();
- host.addChild(context);
- host.setName("localhost");
- host.setAppBase("webapps");
-
- connector.setContainer(host);
支持多个Host(虚拟机)
- SimpleEngine engine = new SimpleEngine();
- engine.addChild(host);
- engine.setDefaultHost("localhost");
-
- connector.setContainer(engine);
Catalina启动或关闭的时候,它的组件也一起启动或关闭
Catalina允许一个组件包含其他组件,Catalina启动类只要启动一个组件便可以将应用程序的所有组件启动
Lifecycle接口
BEFORE_START_EVENT、START_EVENT、AFTER_START_EVENT在组件启动时触发
BEFORE_STOP_EVENT、STOP_EVENT、AFTER_STOP_EVENT在组件关闭时触发
Context实现Lifecycle的方式
public class SimpleContext implements Context public interface Context extends Container public interface Container extends Lifecycle
实现addLifecycleListener、findLifecycleListeners、removeLifecycleListener方法
start方法中(启动组件和子容器)
- public void start() throws LifecycleException {
- lifecycle.fireLifecycleEvent(BEFORE_INIT_EVENT,null);
- started=true;
- //启动加载器
- if ((loader != null) && (loader instanceof Lifecycle)) {
- ((Lifecycle) loader).start();
- }
- //启动子容器
- Container children[] = findChildren();
- for (int i = 0; i < children.length; i++) {
- if (children[i] instanceof Lifecycle) {
- ((Lifecycle) children[i]).start();
- }
- }
- //启动pipeline
- if (pipeline instanceof Lifecycle) {
- ((Lifecycle) pipeline).start();
- lifecycle.fireLifecycleEvent(START_EVENT, null);
- }
- lifecycle.fireLifecycleEvent(AFTER_INIT_EVENT, null);
- }

stop方法中(关闭组件和子容器)
- public void stop() throws LifecycleException {
- lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT,null);
- lifecycle.fireLifecycleEvent(STOP_EVENT,null);
- started=false;
- //关闭pipeline
- if (pipeline instanceof Lifecycle) {
- ((Lifecycle) pipeline).stop();
- }
- //关闭子容器
- Container children[] = findChildren();
- for (int i = 0; i < children.length; i++) {
- if (children[i] instanceof Lifecycle) {
- ((Lifecycle) children[i]).stop();
- }
- }
- //关闭加载器
- if ((loader != null) && (loader instanceof Lifecycle)) {
- ((Lifecycle) loader).stop();
- }
- lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);
- }

LifecycleEvent(生命周期事件)
Lifecycle作为入参
LifecycleListener接口(生命周期的事件监听器)
当某个事件监听器监听到相关事件发生时,会调用该方法
LifecycleSupport(帮助管理监听器,并触发相应的生命周期事件)
servlet只允许载入WEB-INF/classes目录及其子目录下的类。和WEB-INFO/lib目录下的库
Logger接口的setContainer和getContainer方法使日志记录器和某个servlet容器相关联
Loader接口的setContainer和getContainer方法使载入器和某个servlet容器相关联
或context的setLoader方法使载入器和某个servlet容器相关联
Loader loader =new WebAppLoader() context.setLoader(loader)
Logger接口的setContainer和getContainer方法使日志记录器和某个servlet容器相关联
或context的setLogger方法使日志记录器和某个servlet容器相关联
SystemOutLogger、SystemErrLogger、FileLogger
Bootstrap中
System.setProperties("catalina.base", System.getProperties("user.dir")); FileLogger logger = new FileLogger(); logger.setPrefix("FileLog_"); logger.setSuffix(".txt"); logger.setTimeStamp(true); logger.setDirectory("webroot"); context.setLogger(logger);
Manager接口的setContainer和getContainer方法使管理器和某个servlet容器相关联
或context的setManager方法使管理器和某个servlet容器相关联
一个阀(验证器),对当前用户进行身份验证,验证器调用context的领域对象的authenticate()方法验证
context的setRealm方法使管理器和某个servlet容器相关联
服务器组件提供一种优雅的方式启动和关闭整个Catalina部署(initialize、start、stop、await方法)(addService方法添加服务组件)
服务组件封装了servlet容器和连接器之间的关系(可以有一个servlet容器和多个连接器组成)
- StandardService service = new StandardService();
- service.setName("Stand-alone Service");
- StandardServer server = new StandardServer();
- server.addService(service);
- service.setContainer(engine);
- service.addConnector(connector);
- if (server instanceof Lifecycle) {
- try {
- server.initialize();
- ((Lifecycle) server).start();
- server.await();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
用来部署和安装Web应用程序,是Deployer接口的实例
要使用一个Web应用程序,必须要将表示该应用程序的Context实例部署到一个Host实例中。在Tomcat中,Context实例可以用WAR文件的形式部署,也可以将整个Web应用程序复制到Tomcat安装目录下的webapp下,对于部署的每个应用程序,可以在其中包含一个描述符文件,该文件包含Context实例的配置信息,描述符文件采用xml文档格式。
HostConfig类型的生命周期监听器,来将Context实例添加到Host实例中。HostConfig实例的start方法会逐个部署和安装指定目录中的所有Web应用程序,HostConfig类的start方法有deployApps方法,deployApps方法中会调用deployDescriptors()、deployWARs()、deployDirectories()方法来部署Context实例(web应用程序)
在正常关闭(System.exit()或程序的最后一个非守护进程线程退出)和虚拟机突然中断时,虚拟机启动所有已经注册的关闭钩子(关闭钩子是先前已经通过Runtime类注册的线程),所有关闭钩子会并发执行,直到完成任务。然后虚拟机根据情况调用所有没有被调用过的终结器。(无论用户如何关闭应用程序,清理代码总是能够得到执行)
创建关闭钩子
- public class ShutdownHook extends Thread{
-
- @Override
- public void run() {
- System.out.println("shutdown");
- }
- }
- ShutdownHook shutdownHook = new ShutdownHook();
- Runtime.getRuntime().addShutdownHook(shutdownHook);
Catalina类用于启动和关闭Server对象,并负责解析Tomcat配置文件(server.xml)
Catalina包含一个Digester对象解析server.xml,一个Server对象,Server对象有一个Service对象,Service对象包含一个Servlet容器和一个或多个连接器
Bootstrap类是一个入口点,负责创建Catalina实例,并调用process()方法,作为一个独立的应用程序运行Tomcat。
Manager应用程序用于管理已经部署的Web应用程序(如显示已部署Web应用程序信息)
JMX(java manager extensions)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。