Tomcat知识点(深入剖析Tomcat学习笔记)

servlet容器的3步操作

  1. 创建一个request对象
  2. 创建一个调用Servlet的response对象,用来向Web客户端发送响应
  3. 调用Servlet的service()方法

Catalina是一种Servlet容器

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

    }
}

Tomcat中的连接器

容器

处理请求servlet资源,并为Web客户端填充填充response对象

容器与连接器的连接关系

HttpConnector connector = new HttpConnector();
SimpleContainer container = new SimpleContainer();
connector.setContainer(container);

4种类型的容器(Engine、Host、Context、Wrapper)

  1. Engine:表示整个Catalina servlet引擎
  2. Host:表示包含有一个或多个context容器的虚拟主机
  3. Context:表示一个Web应用程序,一个Context可以有多个Wrapper
  4. Wrapper:表示一个独立的servlet

Engine>Host>Context>Wrapper(包含关系)

容器中的管道任务

4个接口:Pipeline(addValve方法添加阀)、Valve(阀,用来处理接收到的请求)、ValveContext(实现依次调用阀)、Contained(限制至多与一个servlet容器相关联)

一个servlet容器中有一条管道,当调用容器的invoke方法,容器会将处理工作交给管道处理,管道会从第一个阀开始,依次执行任务,知道所有任务执行完成为止(调用ValveContext实例的invokeNext方法)

Wrapper(一个独立的servlet)

  1. 管理基础servlet生命周期(调用servlet的init()、service()、destroy()等方法)
  2. Wrapper是最低级的servlet容器,不能再向其中添加子容器
  3. load()载入并初始化servlet类
  4. allocate()分配一个已经初始化的servlet实例

一个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(一个Web应用程序)

  1. 一个Context实例可以有一个或多个Wrapper实例作为子容器
  2. addWrapper()方法和createWrapper()方法

一个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();
        }
    }

原理

  1. 容器中包含一个管道,容器的invoke方法会调用管道的invoke方法(如:SimpleContext类的invoke方法调用pipeline的invoke方法)

  2. 管道的invoke方法会调用所有添加到其容器中的阀,再调用其基础阀的invoke方法(pipeline的invoke方法调用pipelineValveContext的invokeNext,包含ContextValve的invoke方法)

  3. 在Wrapper实例中,基础阀负责载入相关联的servlet类,并对请求进行响应(ContextValve的invoke方法)

  4. 在包含子容器的Context实例中,基础阀使用映射器来查找一个子容器,该子容器负责处理接收到的请求,若找到相应的子容器,则调用器invoke方法,转到步骤1继续执行(ContextValve的invoke方法中,context.map(request,true),分配servlet实例,并调用它的service()方法)

  5. context.map方法中

    String name = context.findServletMapping(relativeURI) wrapper = (Wrapper) context.findChild(name)
    

    start具体步骤

Host(包含有一个或多个context容器的虚拟主机)

若一个Context实例使用ContextConfig对象进行设置,就必须使用一个Host对象,使用ContextConfig对象需要知道应用程序web.xml文件的位置,这里代码显示Context实例需要一个Host实例作为其父容器

        StandardHost host = new StandardHost();
        host.addChild(context);
        host.setName("localhost");
        host.setAppBase("webapps");
      
        connector.setContainer(host);

Engine(一个独立的servlet)

支持多个Host(虚拟机)

        SimpleEngine engine = new SimpleEngine();
        engine.addChild(host);
        engine.setDefaultHost("localhost");
        
        connector.setContainer(engine);

容器的生命周期管理

Catalina启动或关闭的时候,它的组件也一起启动或关闭

Catalina允许一个组件包含其他组件,Catalina启动类只要启动一个组件便可以将应用程序的所有组件启动

Lifecycle、LifecycleEvent、LifecycleListener、LifecycleSupport

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(帮助管理监听器,并触发相应的生命周期事件)

容器的组件

载入器(Loader)

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)

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

Session 管理器(Manager)

Manager接口的setContainer和getContainer方法使管理器和某个servlet容器相关联

或context的setManager方法使管理器和某个servlet容器相关联

领域(Realm)(保证安全性)

一个阀(验证器),对当前用户进行身份验证,验证器调用context的领域对象的authenticate()方法验证

context的setRealm方法使管理器和某个servlet容器相关联

资源(Resource)

服务器组件和服务组件(serve和service)

服务器组件提供一种优雅的方式启动和关闭整个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();
            }
        }

Digester库(用来将XML文档中的元素转换成java对象)

部署器

用来部署和安装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类注册的线程),所有关闭钩子会并发执行,直到完成任务。然后虚拟机根据情况调用所有没有被调用过的终结器。(无论用户如何关闭应用程序,清理代码总是能够得到执行)

创建关闭钩子

  1. 创建一个Thread类的子类,实现子类的run方法
  2. 在应用程序中实例化关闭钩子类
  3. 在当前Runtime类的addShutdownHook方法注册关闭钩子
public class ShutdownHook extends Thread{

    @Override
    public void run() {
        System.out.println("shutdown");
    }
}
ShutdownHook shutdownHook = new ShutdownHook();
Runtime.getRuntime().addShutdownHook(shutdownHook);

启动Tomcat(Catalina类和Bootstrap类)

Catalina类用于启动和关闭Server对象,并负责解析Tomcat配置文件(server.xml)

Catalina包含一个Digester对象解析server.xml,一个Server对象,Server对象有一个Service对象,Service对象包含一个Servlet容器和一个或多个连接器

Bootstrap类是一个入口点,负责创建Catalina实例,并调用process()方法,作为一个独立的应用程序运行Tomcat。

Manager应用程序的Servlet类

Manager应用程序用于管理已经部署的Web应用程序(如显示已部署Web应用程序信息)

基于JMX的管理

JMX(java manager extensions)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值