`
hyw520110
  • 浏览: 218680 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

[How Tomcat Works]第2章 一个简单的Servlet容器

    博客分类:
  • java
阅读更多

译者 jarfield

博客 http://jarfield.iteye.com

概述

   本章通过两个应用程序,介绍了如何开发你自己的Servlet 容器。为了让你容易Servlet 容器的工作原理,第一个应用程序被设计地尽可能简单,然后演化为稍微复杂一些的第二个Servlet 容器。

    提示:每章的Servlet 容器都是在前一章的基础上逐步演化的,到第17 章就变成了一个羽翼丰满(full-functional )的Tomcat Servlet 容器。

    本章的两个Servlet 容器,既能够运行简单的Servlet ,也能够处理静态资源。你可以使用 PrimitiveServlet 来测试本章的Servlet 容器 PrimitiveServlet 类的代码在 Listing 2.1 中,源代码文件在webroot 目录下。本章的Servlet 容器还不能运行更加复杂的Servlet ,不过你在下一章就可以学到如何构建更加成熟的Servlet 容器。
Listing 2.1: PrimitiveServlet.java

Java代码 复制代码
  1. import javax.servlet.*;   
  2. import java.io.IOException;   
  3. import java.io.PrintWriter;   
  4.     
  5. public class PrimitiveServlet implements Servlet {   
  6.     
  7.    public void init(ServletConfig config) throws ServletException {   
  8.      System.out.println("init");   
  9.    }   
  10.     
  11.    public void service(ServletRequest request, ServletResponse response)   
  12.      throws ServletException, IOException {   
  13.      System.out.println("from service");   
  14.      PrintWriter out = response.getWriter();   
  15.      out.println("Hello. Roses are red.");   
  16.      out.print("Violets are blue.");   
  17.    }   
  18.     
  19.     public void destroy() {   
  20.      System.out.println("destroy");   
  21.    }   
  22.     public String getServletInfo() {   
  23.      return null;   
  24.    }   
  25.    public ServletConfig getServletConfig() {   
  26.      return null;   
  27.    }   
  28. }   
import javax.servlet.*;
import java.io.IOException;
import java.io.PrintWriter;
 
public class PrimitiveServlet implements Servlet {
 
   public void init(ServletConfig config) throws ServletException {
     System.out.println("init");
   }
 
   public void service(ServletRequest request, ServletResponse response)
     throws ServletException, IOException {
     System.out.println("from service");
     PrintWriter out = response.getWriter();
     out.println("Hello. Roses are red.");
     out.print("Violets are blue.");
   }
 
    public void destroy() {
     System.out.println("destroy");
   }
    public String getServletInfo() {
     return null;
   }
   public ServletConfig getServletConfig() {
     return null;
   }
} 
 
Java代码 复制代码
  1. import javax.servlet.*;   
  2. import java.io.IOException;   
  3. import java.io.PrintWriter;   
  4.     
  5. public class PrimitiveServlet implements Servlet {   
  6.     
  7.    public void init(ServletConfig config) throws ServletException {   
  8.      System.out.println("init");   
  9.    }   
  10.     
  11.    public void service(ServletRequest request, ServletResponse response)   
  12.      throws ServletException, IOException {   
  13.      System.out.println("from service");   
  14.      PrintWriter out = response.getWriter();   
  15.      out.println("Hello. Roses are red.");   
  16.      out.print("Violets are blue.");   
  17.    }   
  18.     
  19.     public void destroy() {   
  20.      System.out.println("destroy");   
  21.    }   
  22.   
  23.     public String getServletInfo() {   
  24.      return null;   
  25.    }   
  26.   
  27.    public ServletConfig getServletConfig() {   
  28.      return null;   
  29.    }   
  30. }   
import javax.servlet.*;
import java.io.IOException;
import java.io.PrintWriter;
 
public class PrimitiveServlet implements Servlet {
 
   public void init(ServletConfig config) throws ServletException {
     System.out.println("init");
   }
 
   public void service(ServletRequest request, ServletResponse response)
     throws ServletException, IOException {
     System.out.println("from service");
     PrintWriter out = response.getWriter();
     out.println("Hello. Roses are red.");
     out.print("Violets are blue.");
   }
 
    public void destroy() {
     System.out.println("destroy");
   }

    public String getServletInfo() {
     return null;
   }

   public ServletConfig getServletConfig() {
     return null;
   }
} 
 

    本章两个应用(Servlet 容器)的类都在 ex02.pyrmont 包中。为了理解这两个应用是如何工作的,你需要熟悉 javax.servlet.Servlet 接口。因此,本章的第一节先讨论该接口。然后你将学习到,为了处理到ServletHTTP 请求,Servlet 容器必须做哪些事情。

javax.servlet.Servlet 接口

    Servlet 编程主要涉及到javax.servletjavax.servlet.http 这两个包中的类和接口。在这些类和接口中,javax.servlet.Servlet 接口是最重要的。所有的Servlet 都必须实现该接口,或继承该接口的实现类。

    Servlet 接口有5 个方法,它们的原型如下所示。

Java代码 复制代码
  1. public void init(ServletConfig config) throws ServletException   
  2. public void service(ServletRequest request, ServletResponse response)   
  3.    throws ServletException, java.io.IOException   
  4. public void destroy()   
  5. public ServletConfig getServletConfig()   
  6. public java.lang.String getServletInfo()  
public void init(ServletConfig config) throws ServletException
public void service(ServletRequest request, ServletResponse response)
   throws ServletException, java.io.IOException
public void destroy()
public ServletConfig getServletConfig()
public java.lang.String getServletInfo()
Java代码 复制代码
  1. public void init(ServletConfig config) throws ServletException   
  2. public void service(ServletRequest request, ServletResponse response)   
  3.    throws ServletException, java.io.IOException   
  4. public void destroy()   
  5. public ServletConfig getServletConfig()   
  6. public java.lang.String getServletInfo()   
public void init(ServletConfig config) throws ServletException
public void service(ServletRequest request, ServletResponse response)
   throws ServletException, java.io.IOException
public void destroy()
public ServletConfig getServletConfig()
public java.lang.String getServletInfo() 


    在上面5个方法中,initservicedestroySerlvet 的生命周期方法。 Serlvet 容器初始化Servlet 之后会调用 init 方法。Servlet 容器只调用该方法一次,以表明Servlet 可以投入使用了。 init 方法执行成功前,Servlet 不可以接收任何请求。Servlet 程序员可以重写(override )该方法,以添加仅需执行一次的代码,例如加载数据库驱动、初始化一些变量的值等等。其它情况下,该方法一般留空。

    接收到请求之后,Servlet 容器以一个 javax.servlet.ServletRequest 对象和一个 javax.servlet.ServletResponse 对象为参数,调用Servlet service 方法。ServletRequest 对象包含了客户端的请求信息,而ServletResponse 对象封装了Servlet 的响应。service 方法在 Servlet的生命周期中可以被调用多次。
   
    在移除Servlet 实例之前,Servlet 容器会调用dest r oy 方法。这通常发生在Servlet 容器关闭或内存不够的时候。该方法只有在所有线程都退出 service 方法或超时之后,才能被调用。Serlvet 容器调用了一个Servlet destroy 方法之后,就不会调用该Servlet service 方法。 destroy 方法给了Servlet 一个机会,用来清理持有的资源,例如内存、文件句柄和线程,还可以用来持久化Servlet 的状态。

    Listing 2.1 PrimitiveServlet 类的代码, 该Serlvet 非常简单,我们用它来测试本章的Serlvet 容器。 PrimitiveServlet 实现了 javax.servlet.Servlet 接口 (就像所有Servlet都必须做的那样),提供了所有Servlet 接口所有5 个方法的实现。每次调用 init service destroy 方法, PrimitiveServlet 都把方法名打印到标准控制台。 另外, service 方法从 ServletResponse 对象中获取了 java.io.PrintWriter 对象,用来向浏览器发送字符串。

第一个应用

    现在,让我们从Servlet 容器的视角来看看Servlet 编程。简而言之,一个功能完全的Serlvet 容器需要为每个HTTP 请求做以下的事情:

  • Servlet 第一次被调用时,加载Serlvet 类,并调用Serlvetinit 方法(只调用一次)。
  • 为每个请求,创建一个javax.servlet.ServletRequest 对象和一个javax.servlet.ServletResponse 对象。
  • ServletRequest 对象和ServletResponse 为参数,调用Servletservice 方法。
  • Servlet 被关闭时,调用Servletdestroy 方法,卸载(unloadServlet 类。

    本章的第一个Servlet 容器不是功能完全。因此,它只能运行简单的Servlet ,没有调用 init destroy 方法。相反,它做了以下事情:

  • 等待HTTP 请求。
  • 创建一个ServletRequest 对象和一个ServletResponse 对象。
  • 如果请求的是静态资源,就以ServletRequest 对象和ServletResposne 对象为参数,调用StaticResourceProcessor 对象的process 方法。
  • 如果请求的是Servlet ,就加载Servlet 类,并以ServletRequest 对象和ServletResposne 对象为参数,调用Servletservice 方法。

    提示:在这个Servlet 容器中,每次请求ServletServlet 类都会被加载。

    第一个Servlet 容器共包含6 个类:

  • HttpServer1
  • Request
  • Response
  • StaticResourceProcessor
  • ServletProcessor1
  • Constants

    Figure 2.1 描绘了第一个 Servlet 容器的 UML

    该应用的入口(静态 main 方法)在 HttpServer1 类中。 main 方法创建了 HttpServer1 的一个实例,并且调用了它的 await 方法。 await 方法在等待HTTP 请求,并为每个请求创建一个 Request 对象和 Response 对象,然后将它们派发(dispatch )到 StaticResourceProcessor 对象或 ServletProcessor 对象,派发的依据是:请求的内容是静态资源还是Servlet

                    Figure 2.1: The UML diagram of the first servlet container


    Constants 类包含了被其他类引用的静态常量 WEB_ROOT 。容器可以提供 PrimitiveServlet 和静态资源, WEB_ROOT 就指定了 PrimitiveServlet 和静态资源所在的目录。

     HttpServer1 对象一直等待HTTP 请求,直到接收到shutdown 命令位置。你可以用1中的方法发送shutdowm 命令。

    本应用的每个类会在以下各小节中进行讨论。

HttpServer1

    本应用的 HttpServer1 类,和1简单Web 服务器中的 HttpServer 类很类似。不过, HttpServer1 类既可以处理静态资源,又可以处理Servlet 。要请求一个静态资源,你可以在浏览器地址栏中敲入下面的URL:

Html代码 复制代码
  1. http://machineName:port/staticResource      
http://machineName:port/staticResource    
 

    这就是你在 1 中请求静态资源的方法。

    要请求 Servlet ,你可以使用下面的 URL

Html代码 复制代码
  1. http://machineName:port/servlet/servletClass      
http://machineName:port/servlet/servletClass    


    因此,如果你使用本地浏览器请求名为 PrimitiveServlet Serlvet , 你可以在浏览器地址栏中敲入下面的URL

Html代码 复制代码
  1. http://localhost:8080/servlet/PrimitiveServlet  
http://localhost:8080/servlet/PrimitiveServlet
 

    Servlet 容器可以提供 PrimitiveServlet 。但是,如果你调用其他的Servlet ,比如 ModernServlet Servlet 容器就会抛出异常。下一章,你将会构建同时提供这两个Servlet 的应用。

    HttpServer1 类的代码在 Listing 2.2 中。
Listing 2.2: The HttpServer1 Class's await method

 
Java代码 复制代码
  1. package ex02.pyrmont;   
  2.     
  3. import java.net.Socket;   
  4. import java.net.ServerSocket;   
  5. import java.net.InetAddress; import java.io.InputStream;   
  6. import java.io.OutputStream;   
  7. import java.io.IOException;   
  8.     
  9. public class HttpServer1 {   
  10.     
  11.    /** WEB_ROOT is the directory where our HTML and other files reside.  
  12.     *  For this package, WEB_ROOT is the "webroot" directory under the  
  13.     *  working directory.  
  14.     *  The working directory is the location in the file system  
  15.     *  from where the java command was invoked.  
  16.     */  
  17.    // shutdown command   
  18.    private static final String SHUTDOWN_COMMAND = "/SHUTDOWN";   
  19.     
  20.    // the shutdown command received   
  21.    private boolean shutdown = false;   
  22.     
  23.    public static void main(String[] args) {   
  24.      HttpServer1 server = new HttpServer1();   
  25.      server.await();   
  26.    }   
  27.     
  28.    public void await() {   
  29.      ServerSocket serverSocket = null;   
  30.      int port = 8080;   
  31.      try {   
  32.       serverSocket =  new ServerSocket(port, 1,   
  33.         InetAddress.getByName("127.0.0.1"));   
  34.      }   
  35.     
  36.      catch (IOException e) {   
  37.        e.printStackTrace();   
  38.        System.exit(1);   
  39.      }   
  40.     
  41.      // Loop waiting for a request   
  42.      while (!shutdown) {   
  43.        Socket socket = null;   
  44.        InputStream input = null;   
  45.        OutputStream output = null;   
  46.        try {   
  47.          socket = serverSocket.accept();   
  48.          input = socket.getInputstream();            
  49.          output = socket.getOutputStream();   
  50.     
  51.          // create Request object and parse   
  52.          Request request = new Request(input);   
  53.          request.parse();   
  54.     
  55.          // create Response object   
  56.          Response response = new Response(output);   
  57.          response.setRequest(request);   
  58.     
  59.          // check if this is a request for a servlet or   
  60.          // a static resource   
  61.          // a request for a servlet begins with "/servlet/"   
  62.          if (request.getUri().startsWith("/servlet/")) {   
  63.            ServletProcessor1 processor = new ServletProcessor1();   
  64.            processor.process(request, response);   
  65.          }   
  66.          else {   
  67.            StaticResoureProcessor processor =   
  68.              new StaticResourceProcessor();   
  69.            processor.process(request, response);   
  70.          }   
  71.     
  72.           // Close the socket   
  73.          socket.close();   
  74.          //check if the previous URI is a shutdown command   
  75.          shutdown = request.getUri().equals(SHUTDOWN_COMMAND);   
  76.        }   
  77.        catch (Exception e) {   
  78.          e.printStackTrace();   
  79.          System.exit(1);   
  80.        }   
  81.      }   
  82.    }   
  83. }  
package ex02.pyrmont;
 
import java.net.Socket;
import java.net.ServerSocket;
import java.net.InetAddress; import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;
 
public class HttpServer1 {
 
   /** WEB_ROOT is the directory where our HTML and other files reside.
    *  For this package, WEB_ROOT is the "webroot" directory under the
    *  working directory.
    *  The working directory is the location in the file system
    *  from where the java command was invoked.
    */
   // shutdown command
   private static final String SHUTDOWN_COMMAND = "/SHUTDOWN";
 
   // the shutdown command received
   private boolean shutdown = false;
 
   public static void main(String[] args) {
     HttpServer1 server = new HttpServer1();
     server.await();
   }
 
   public void await() {
     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);
     }
 
     // Loop waiting for a request
     while (!shutdown) {
       Socket socket = null;
       InputStream input = null;
       OutputStream output = null;
       try {
         socket = serverSocket.accept();
         input = socket.getInputstream();         
         output = socket.getOutputStream();
 
         // create Request object and parse
         Request request = new Request(input);
         request.parse();
 
         // create Response object
         Response response = new Response(output);
         response.setRequest(request);
 
         // check if this is a request for a servlet or
         // a static resource
         // a request for a servlet begins with "/servlet/"
         if (request.getUri().startsWith("/servlet/")) {
           ServletProcessor1 processor = new ServletProcessor1();
           processor.process(request, response);
         }
         else {
           StaticResoureProcessor processor =
             new StaticResourceProcessor();
           processor.process(request, response);
         }
 
          // Close the socket
         socket.close();
         //check if the previous URI is a shutdown command
         shutdown = request.getUri().equals(SHUTDOWN_COMMAND);
       }
       catch (Exception e) {
         e.printStackTrace();
         System.exit(1);
       }
     }
   }
}
 

    await 方法等待HTTP 请求,直到接收到shutdown 命令为止,这会让你想起1 await 方法。 Listing 2.2 中的 await 方法和1的区别在于, Listing 2.2 的请求既可以派发到 StaticResourceProcessor 对象,又可以派发都 ServletProcessor 对象。如果请求的URI /servlet/ 开头,那么就会被派发到 ServletProcessor 对象。否则,请求将被派发到 StaticResourceProcessor 对象。注意 Listing 2.2 中灰色的部分(59行~70行)。

Request

    Servlet service 方法从容器接收一个 javax.servlet.ServletRequest 对象和一个 javax.servlet.ServletResponse 对象作为参数。这也就是说,对每个HTTP 请求,Servlet 容器都必须创建一个 ServletRequest 对象和 ServletResponse 对象,并将它们传递给处理该请求的Servlet service 方法。
   
    ex02.pyrmont.Request 类代表了传递给Servlet service 方法的请求对象。因此,它必须实现 javax.servlet.ServletRequest 接口。 Request 类必须提供 ServletRequest 接口所有方法的实现。不过,我们想让 Reuqest 尽量简单,只实现其中一些方法,在后面章节再实现所有的方法。为了通过编译 ,你必须提供这些方法的“空”实现。从 Listing 2.3 可以看出,所有返回值类型为 Object 的方法都返回 null
Listing 2.3: The Request class

Java代码 复制代码
  1. package ex02.pyrmont;   
  2.     
  3. import java.io.InputStream;   
  4. import java.io.IOException;   
  5. import java.io.BufferedReader;   
  6. import java.io.UnsupportedEncodingException;   
  7. import java.util.Enumeration;   
  8. import java.util.Locale;   
  9. import java.util.Map;   
  10. import javax.servlet.RequestDispatcher;   
  11. import javax.servlet.ServletInputStream;   
  12. import javax.servlet.ServletRequest;   
  13.     
  14.     
  15. public class Request implements ServletRequest {   
  16.     
  17.    private InputStream input;   
  18.    private String uri;   
  19.     
  20.    public Request(InputStream input){   
  21.      this.input = input;    }   
  22.     
  23.    public String getUri() {   
  24.      return uri;   
  25.    }   
  26.     
  27.    private String parseUri(String requestString) {   
  28.      int index1, index2;   
  29.      index1 = requestString.indexOf(' ');   
  30.      if (index1 != -1) {   
  31.        index2 = requestString.indexOf(' ', index1 + 1);   
  32.        if (index2 > index1)   
  33.          return requestString.substring(index1 + 1, index2);   
  34.      }   
  35.      return null;   
  36.    }   
  37.     
  38.    public void parse() {   
  39.      // Read a set of characters from the socket   
  40.      StringBuffer request = new StringBuffer(2048);   
  41.      int i;   
  42.      byte[] buffer = new byte[2048];   
  43.      try {   
  44.        i = input.read(buffer);   
  45.      }   
  46.      catch (IOException e) {   
  47.        e.printStackTrace();   
  48.        i = -1;   
  49.      }   
  50.      for (int j=0; j<i; j++) {   
  51.        request.append((char) buffer(j));   
  52.      }   
  53.      System.out.print(request.toString());   
  54.      uri = parseUri(request.toString());   
  55.    }   
  56.     
  57.    /* implementation of ServletRequest */  
  58.    public Object getAttribute(String attribute) {   
  59.      return null;   
  60.    }   
  61.    public Enumeration getAttributeNames() {   
  62.      return null;   
  63.    }   
  64.    public String getRealPath(String path) {      return null;   
  65.    }   
  66.    public RequestDispatcher getRequestDispatcher(String path) {   
  67.      return null;   
  68.    }   
  69.    public boolean isSecure() {   
  70.      return false;   
  71.    }   
  72.    public String getCharacterEncoding() {   
  73.      return null;   
  74.    }   
  75.    public int getContentLength() {   
  76.      return 0;   
  77.    }   
  78.     
  79.    public String getContentType() {   
  80.      return null;   
  81.    }   
  82.    public ServletInputStream getInputStream() throws IOException {   
  83.      return k
    分享到:
    评论

相关推荐

    译How Tomcat Works(第二章)

    《译How Tomcat Works(第二章)》这篇文章主要讲解了Apache Tomcat服务器的工作原理,它是一个开源的Java Servlet容器,广泛用于部署Web应用程序。在这一章中,我们将深入探讨Tomcat如何处理HTTP请求,以及其内部架构...

    HowTomcatWorks(书和源码)

    《How Tomcat Works》是一本深入解析Apache Tomcat工作原理的书籍,同时也包含了源码,为读者提供了理论与实践相结合的深入学习体验。Tomcat是一款广泛使用的开源Java Servlet容器,它是Apache软件基金会 Jakarta...

    WEB服务器工作机制由浅至深(2):【How Tomcat Works】1~4章翻译分析

    本篇文章将深入探讨Tomcat,一个广泛使用的Java Web服务器,通过翻译分析"How Tomcat Works"一书的前四章内容,来理解其工作机制。 首先,我们要了解Tomcat的基本架构。Tomcat是Apache软件基金会的Jakarta项目中的...

    how tomcat works

    Apache Tomcat是一个开源的Java Servlet容器,它实现了Java Servlet和JavaServer Pages技术规范,提供了Java Web服务器的功能。对于Java Web开发者,尤其是那些希望深入了解Web容器工作原理的学习者而言,这本书是一...

    译How Tomcat Works(第四章)

    《译How Tomcat Works(第四章)》这篇文章深入解析了Apache Tomcat服务器的工作原理,主要聚焦于Tomcat的内部机制,对于理解Web应用容器的运行方式具有重要意义。Tomcat是Java Servlet和JavaServer Pages(JSP)...

    howtomcatworks tomcat运行内幕

    本篇文章将深入剖析"HowTomcatWorks",帮助读者全面理解Tomcat的内部工作机制。 1. **Tomcat架构概述** Tomcat由一系列组件构成,包括Catalina(核心Servlet容器)、Jasper(JSP引擎)、 Coyote(HTTP/HTTPS连接器...

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

    通过对《How Tomcat Works》一书第11章的翻译与分析,我们将揭示StandardWrapper如何工作,以及它对整个Web应用的影响。 首先,我们需要了解Servlet的生命周期。Servlet在Web应用中扮演着动态处理请求的角色,它们...

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

    通过阅读和分析《How Tomcat Works》的第12章,我们可以更深入地了解Tomcat如何处理请求,管理Web应用,并为开发者提供一个强大的平台来构建和运行Java Web应用程序。这有助于我们更好地利用Tomcat的特性,提高应用...

    WEB服务器工作机制由浅至深(8):【How Tomcat Works】第14章Server和Service

    《WEB服务器工作机制由浅至深(8):【How Tomcat Works】第14章Server和Service》 在深入探讨Web服务器的工作机制时,Tomcat作为Apache软件基金会的开源Java Servlet容器,扮演着至关重要的角色。本章将聚焦于Tomcat...

    How Tomcat Works 高清中文版

    1. **Tomcat简介**:Tomcat是Apache软件基金会的Jakarta项目下的一个开源应用服务器,主要负责运行Java Servlet和JavaServer Pages (JSP)。作为轻量级的Web服务器和应用服务器,Tomcat因其简单、高效而被广泛使用。 ...

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

    本文将深入探讨Tomcat的工作机制,基于"How Tomcat Works"的第五章和第六章进行翻译和分析。 第五章主要讨论了Tomcat的生命周期管理和容器概念。在Tomcat中,每个应用都有一个对应的Context,它管理Servlet的加载、...

    How Tomcat Works: A Guide to Developing Your Own Java Servlet Container

    第2章 一个简单的servlet容器 7 2.1 简述 7 2.2 javax.servlet.Servlet接口 7 2.3 Application 1 7 2.3.1 HttpServer1类 8 2.3.2 Request类 8 2.3.3 Response类 9 2.3.4 StaticResourceProcessor类 9 2.3.5 ...

    WEB服务器工作机制由浅至深(9):【How Tomcat Works】第16章关闭钩子以及之后的章节简述

    【WEB服务器工作机制由浅至深(9):【How Tomcat Works】第16章 关闭钩子以及之后的章节简述】 在深入探讨Tomcat服务器的工作机制时,我们来到了第16章,这一章主要讨论了“关闭钩子”(Shutdown Hooks)的概念及其在...

    WEB服务器工作机制由浅至深(7):【How Tomcat Works】第13章Host和Engine

    Tomcat的源码是开放的,这对于开发者来说是一个宝贵的资源,可以学习到如何设计和实现一个高性能的WEB服务器。同时,工具如JMX(Java Management Extensions)可以帮助监控和管理Tomcat的运行状态,包括Engine、Host...

Global site tag (gtag.js) - Google Analytics