• 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对象

    连接器

    连接器的基本操作

    连接服务器

    1. public class HttpConnector implements Runnable {
    2. boolean stopped;
    3. private String scheme = "http";
    4. @Override
    5. public void run() {
    6. ServerSocket serverSocket = null;
    7. int port = 8080;
    8. try {
    9. serverSocket = new ServerSocket(port, 1, InetAddress.getByName("127.0.0.1"));
    10. } catch (IOException e) {
    11. e.printStackTrace();
    12. System.exit(1);
    13. }
    14. while (!stopped) {
    15. Socket socket = null;
    16. try {
    17. socket = serverSocket.accept();
    18. } catch (IOException e) {
    19. e.printStackTrace();
    20. }
    21. HttpProcessor processor = new HttpProcessor(this);
    22. processor.process(socket);
    23. }
    24. }
    25. public void start() {
    26. Thread thread = new Thread(this);
    27. thread.start();
    28. }
    29. }

    处理

    1. public class HttpProcessor {
    2. private HttpConnector httpConnector;
    3. private HttpRequest request;
    4. private HttpResponse response;
    5. public HttpProcessor(HttpConnector httpConnector) {
    6. this.httpConnector = httpConnector;
    7. }
    8. public void process(Socket socket) {
    9. SocketInputStream inputStream = null;
    10. OutputStream outputStream = null;
    11. try {
    12. inputStream = new SocketInputStream(socket.getInputStream(), 2048);
    13. outputStream = socket.getOutputStream();
    14. request = new HttpRequest(inputStream);
    15. response=new HttpResponse(outputStream);
    16. response.setRequest(request);
    17. response.setHeader("Server", "Jsq Servlet Container");
    18. parseRequest(inputStream, outputStream);
    19. parseHeader(inputStream);
    20. if (request.getRequestURI().startWith("/servlet/")) {
    21. ServletProcessor processor = new ServletProcessor();
    22. processor.process(request,response);
    23. }else{
    24. StaticResourceProcessor processor = new StaticResourceProcessor();
    25. processor.process(request, response);
    26. }
    27. socket.close();
    28. } catch (IOException e) {
    29. e.printStackTrace();
    30. }
    31. }
    32. }

    Tomcat中的连接器

    容器

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

    容器与连接器的连接关系

    1. HttpConnector connector = new HttpConnector();
    2. SimpleContainer container = new SimpleContainer();
    3. 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的实现

    1. public static void main(String[] args) {
    2. HttpConnector connector = new HttpConnector();
    3. SimpleWrapper wrapper = new SimpleWrapper();
    4. wrapper.setServletClass("ModernServlet");
    5. SimpleLoader loader = new SimpleLoader();
    6. HeaderLoggerValve headerLoggerValve = new HeaderLoggerValve();
    7. ClientIPLoggerValve clientIPLoggerValve = new ClientIPLoggerValve();
    8. wrapper.setLoader(loader);
    9. ((Pipeline) wrapper).addValve(headerLoggerValve);
    10. ((Pipeline) wrapper).addValve(clientIPLoggerValve);
    11. connector.setContainer(wrapper);
    12. try {
    13. connector.initialize();
    14. connector.start();
    15. System.in.read();
    16. } catch (IOException e) {
    17. e.printStackTrace();
    18. }
    19. }

    Context(一个Web应用程序)

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

    一个Context实现

    1. public static void main(String[] args) {
    2. HttpConnector connector = new HttpConnector();
    3. SimpleWrapper wrapper1 = new SimpleWrapper();
    4. wrapper1.setName("Modern");
    5. wrapper1.setServletClass("ModernServlet");
    6. SimpleWrapper wrapper2 = new SimpleWrapper();
    7. wrapper2.setName("Primitive");
    8. wrapper2.setServletClass("Primitive");
    9. SimpleContext context = new SimpleContext();
    10. context.addChild(wrapper1);
    11. context.addChild(wrapper2);
    12. HeaderLoggerValve headerLoggerValve = new HeaderLoggerValve();
    13. ClientIPLoggerValve clientIPLoggerValve = new ClientIPLoggerValve();
    14. context.setLoader(loader);
    15. ((Pipeline) context).addValve(headerLoggerValve);
    16. ((Pipeline) context).addValve(clientIPLoggerValve);
    17. SimpleContextMapper mapper = new SimpleContextMapper();
    18. mapper.setProtocol("http");
    19. context.addMapper(mapper);
    20. SimpleLoader loader = new SimpleLoader();
    21. context.setLoader(loader);
    22. context.addServletMapping("/Primitive","Primitive");
    23. context.addServletMapping("/Modern","Modern");
    24. connector.setContainer(context);
    25. try {
    26. connector.initialize();
    27. connector.start();
    28. System.in.read();
    29. } catch (IOException e) {
    30. e.printStackTrace();
    31. }
    32. }

    原理

    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实例作为其父容器

    1. StandardHost host = new StandardHost();
    2. host.addChild(context);
    3. host.setName("localhost");
    4. host.setAppBase("webapps");
    5. connector.setContainer(host);

    Engine(一个独立的servlet)

    支持多个Host(虚拟机)

    1. SimpleEngine engine = new SimpleEngine();
    2. engine.addChild(host);
    3. engine.setDefaultHost("localhost");
    4. 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方法中(启动组件和子容器)

    1. public void start() throws LifecycleException {
    2. lifecycle.fireLifecycleEvent(BEFORE_INIT_EVENT,null);
    3. started=true;
    4. //启动加载器
    5. if ((loader != null) && (loader instanceof Lifecycle)) {
    6. ((Lifecycle) loader).start();
    7. }
    8. //启动子容器
    9. Container children[] = findChildren();
    10. for (int i = 0; i < children.length; i++) {
    11. if (children[i] instanceof Lifecycle) {
    12. ((Lifecycle) children[i]).start();
    13. }
    14. }
    15. //启动pipeline
    16. if (pipeline instanceof Lifecycle) {
    17. ((Lifecycle) pipeline).start();
    18. lifecycle.fireLifecycleEvent(START_EVENT, null);
    19. }
    20. lifecycle.fireLifecycleEvent(AFTER_INIT_EVENT, null);
    21. }

    stop方法中(关闭组件和子容器)

    1. public void stop() throws LifecycleException {
    2. lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT,null);
    3. lifecycle.fireLifecycleEvent(STOP_EVENT,null);
    4. started=false;
    5. //关闭pipeline
    6. if (pipeline instanceof Lifecycle) {
    7. ((Lifecycle) pipeline).stop();
    8. }
    9. //关闭子容器
    10. Container children[] = findChildren();
    11. for (int i = 0; i < children.length; i++) {
    12. if (children[i] instanceof Lifecycle) {
    13. ((Lifecycle) children[i]).stop();
    14. }
    15. }
    16. //关闭加载器
    17. if ((loader != null) && (loader instanceof Lifecycle)) {
    18. ((Lifecycle) loader).stop();
    19. }
    20. lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);
    21. }

    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容器和多个连接器组成)

    1. StandardService service = new StandardService();
    2. service.setName("Stand-alone Service");
    3. StandardServer server = new StandardServer();
    4. server.addService(service);
    5. service.setContainer(engine);
    6. service.addConnector(connector);
    7. if (server instanceof Lifecycle) {
    8. try {
    9. server.initialize();
    10. ((Lifecycle) server).start();
    11. server.await();
    12. } catch (IOException e) {
    13. e.printStackTrace();
    14. }
    15. }

    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方法注册关闭钩子
    1. public class ShutdownHook extends Thread{
    2. @Override
    3. public void run() {
    4. System.out.println("shutdown");
    5. }
    6. }
    7. ShutdownHook shutdownHook = new ShutdownHook();
    8. 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)

  • 相关阅读:
    c语言实现三子棋
    112. Path Sum刷题笔记
    IPC中的AIDL机制
    Vue中过滤器用法详解
    一文读懂vue3的Pinia
    一种晶圆表面形貌测量方法-无图晶圆几何量测系统
    ES & Kibana windows 安装
    Spring Boot 2.x系列【19】功能篇之自定义Starter 启动器
    Flord算法
    字节研发之道
  • 原文地址:https://blog.csdn.net/jsq916/article/details/126192174