1. 什么是Web服务器

Web服务器一般指网站服务器,是指驻留于因特网上某种类型计算机的程序,可以向浏览器等Web客户端提供文档,也可以放置网站文件,让全世界浏览;可以放置数据文件,让全世界下载。

Web服务器一般使用 HTTP协议与客户机浏览器进行信息交流,这就是人们常把它们称为 HTTP 服务器的原因。
Web服务器

2. 什么是Tomcat

Tomcat是一款开源轻量级Web应用服务器,是一款优秀的Servlet容器实现。

Tomcat是一个Servlet容器实现
Servlet 是一种规范,是 Java 语言实现的一个接口。一般情况下我们说的 Servlet 是指任何实现了这个 Servlet 接口的类。

Servlet执行过程:

  1. 实例化并调用 init() 初始化该 Servlet,一般 Servlet 只初始化一次(只有一个对象)。
  2. 调用 service()(根据请求方法不同调用 doGet() 或者 doPost(),此外还有 doHead()、doPut()、doTrace()、doDelete()、doOptions()、destroy())。
  3. 当 Server 不再需要 Servlet 时(一般当 Server 关闭时),Server 调用 destroy() 。
public interface Servlet {

    public void init(ServletConfig config) throws ServletException;    

    public ServletConfig getServletConfig();
    
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;
	
    public String getServletInfo();
   
    public void destroy();
}

3. Tomcat版本介绍

Tomcat版本
Tomcat 8.5版本特点:

  1. 支持Servlet3.1
  2. 默认采用NIO,移除BIO
  3. 支持NIO2(AIO)
  4. 支持HTTP/2协议
  5. 默认采用异步日志处理

4. Tomcat启动

4.1 一般启动

运行startup.bat/sh

启动成功后日志:
Tomcat启动日志

4.2 IDEA启动

在IDEA中配置参考网上教程。

启动成功后日志:
IDEA中tomcat启动日志

4.3 嵌入式启动

在SpringBoot main() 中嵌入式启动 Tomcat。

启动成功后日志:
在这里插入图片描述

4.4 Debug 启动

使用 DeBug 启动可以对基于生产环境部署的应用进行调试,以解决在开发环境无法重现的 BUG。这个主要是基于 JDK 提供的 JPDA(Java Platform Debugger Architecture、Java 平台调试体系结构)。

  1. 在 catalina.sh 文件中加入以下的配置
CATALINA_OPTS="-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=1099
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false
-Djava.rmi.server.hostname=192.168.19.200
-agentlib:jdwp=transport=dt_socket,address=15833,suspend=n,server=y"
export CATALINA_OPTS
  1. 在 Linux 上启动 tomcat,使用命令启动
./bin/catalina.sh run &
  1. IDEA设置
    Tocmat Debug启动IDEA设置1
    Tocmat Debug启动IDEA设置2
    Tocmat Debug启动IDEA设置3
    Tocmat Debug启动IDEA设置4
    Tocmat Debug启动IDEA设置5
    Tocmat Debug启动IDEA设置6
    Tocmat Debug启动IDEA设置7

5. Tomcat项目部署

5.1 隐式部署

直接放文件夹、war、jar 到 webapps 目录,tomcat 会根据文件夹名称自动生成虚拟路径。需要重启 Tomcat 服务器。

5.2 显式部署

有两种方式:

  1. 添加 context 元素
    server.xml 中的 Host 加入一个 Context(指定路径和文件地址),如:
    <Host name="localhost">
    <Context path="/mustang" docBase="D:\myWeb\comet.war" />
    
    即/mustang 这个虚拟路径映射到了 D:\myWeb\comet 目录下(war 会解压成文件),修改完 server.xml 需要重启 tomcat 服务器。
  2. 创建 xml 文件
    xml 文件
    在 conf/Catalina/localhost 中创建 xml 文件,访问路径为文件名,如:
    在 localhost 目录下新建 mustang.xml,内容为:
<Context docBase="D:\myWeb\comet" />

虚拟目录就是文件名 mustang,path 默认为/mustang,添加 mustang.xml 不需要重启 tomcat 服务器。

6. Tomcat目录结构

Tomcat目录结构

  1. bin
    startup:主要是检查 catalina.bat/sh 执行所需环境,并调用 catalina.bat/sh,启动 tomcat。
    catalina:真正启动 Tomcat 的文件,可以在里面设置 jvm 参数。
    shutdown:关闭 Tomcat。
    configtest:校验 tomcat 配置文件 server.xml 的格式、内容等是否合法、正确。
    service:安装 tomcat 服务,可用 net start tomcat 启动。
    version:查看当前 tomcat 的版本号。

    version.sh、startup.sh、shutdown.sh、configtest.sh 都是对 catalina.sh 的包装,差异在于功能介绍和调用 catalina.sh 时的参数不同。

  2. conf
    web.xml:Tomcat 中所有应用的默认部署描述文件,主要定义了基础的 Servlet 和 MIME 映射(mime-mapping 文件类型,其实就是 Tomcat 处理的文件类型)。如果部署的应用中不包含 web.xml,那么 Tomcat 将使用此文件初始化部署描述,反之,Tomcat 会在启动时将默认描述配置与定义描述配置进行合并。web.xml加载 Tomcat 内置的 Servlet:DefaultServlet(加载 html、js、jpg 等静态文件)、JspServlet 专门处理 jsp。 DefaultServlet
    JspServlet
    context.xml:用于自定义所有 Web 应用均需要加载的 Context 配置,如果 Web 应用指定了自己的 context.xml,那么该文件的配置将被覆盖。context.xml 与 server.xml 中配置 context 区别:server.xml 是不可动态重加载的资源,服务器一旦启动以后,要修改这个文件,得重启服务器才能重新加载。而 context.xml 文件则不然,tomcat服务器会定时扫描这个文件,一旦发现文件被修改(时间戳改变),就会自动重加载这个文件,而不需要重启服务器。

    tomcat-users.xml:配置 Tomcat 的 server 的 manager 信息。

    logging.properties:设置 tomcat 日志。控制输出不输出内容到文件,不能阻止生成文件,阻止文件可用注释掉。

  3. webapps
    存放 web 项目的目录,其中每个文件夹都是一个项目;其中 ROOT 是一个特殊的项目,在地址栏中没有给出项目目录时,对应的就是 ROOT 项目。

  4. lib
    Tomcat 的类库,这个目录中的 jar 所有项目都可以共享。

  5. work
    运行时生成的文件,是通过 webapps 中的项目生成的,最终运行的文件都在这里。

  6. temp
    存放 Tomcat 的临时文件,这个目录下的东西可以在停止 Tomcat 后删除。

  7. logs
    日志目录:
    localhost-xxx.log:Web 应用的内部程序日志
    catalina-xxx.log:控制台日志
    host-manager.xxx.log:Tomcat 管理页面中的 host-manager 的操作日志,建议关闭
    localhost_access_log_xxx.log:用户请求 Tomcat 的访问日志(这个文件在 conf/server.xml 里配置),建议关闭(项目一般使用Nginx)

6.1. server.xml

<?xml version="1.0" encoding="UTF-8"?>
 <!-- Server代表一个 Tomcat 实例。可以包含一个或多个 Services,其中每个Service都有自己的Engines和Connectors。
       port="8005"指定一个端口,这个端口负责监听关闭tomcat的请求
  -->
<Server port="8005" shutdown="SHUTDOWN">
   <!-- 监听器 -->
  <Listener className="org.apache.catalina.startup.VersionLoggerListener" />
  <!-- Security listener. Documentation at /docs/config/listeners.html
  <Listener className="org.apache.catalina.security.SecurityListener" />
  -->
  <!--APR library loader. Documentation at /docs/apr.html -->
  <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
  <!-- Prevent memory leaks due to use of particular java/javax APIs-->
  <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
  <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />

  <!-- 全局命名资源,定义了UserDatabase的一个JNDI(java命名和目录接口),通过pathname的文件得到一个用户授权的内存数据库 -->
  <GlobalNamingResources>
    <!-- Editable user database that can also be used by
         UserDatabaseRealm to authenticate users
    -->
    <Resource name="UserDatabase" auth="Container"
              type="org.apache.catalina.UserDatabase"
              description="User database that can be updated and saved"
              factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
              pathname="conf/tomcat-users.xml" />
  </GlobalNamingResources>

   <!-- Service它包含一个<Engine>元素、一个或多个<Connector>,这些Connector元素共享用同一个Engine元素 -->
  <Service name="Catalina">
    <!--The connectors can use a shared executor, you can define one or more named thread pools-->
    <!--
    <Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
        maxThreads="150" minSpareThreads="4"/>
    -->

     <!-- 
         每个Service可以有一个或多个连接器<Connector>元素,
         第一个Connector元素定义了一个HTTP Connector,它通过8080端口接收HTTP请求;第二个Connector元素定义了一个JD Connector,它通过8009端口接收由其它服务器转发过来的请求。
     -->
	 <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />
	 <!--  NIO2
    <Connector port="8080" protocol="org.apache.coyote.http11.Http11Nio2Protocol"
               connectionTimeout="20000"
               redirectPort="8443" />
			       -->
    <!-- A "Connector" using the shared thread pool-->
    <!--
    <Connector executor="tomcatThreadPool"
               port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />
    -->
    <!-- Define a SSL/TLS HTTP/1.1 Connector on port 8443
         This connector uses the NIO implementation. The default
         SSLImplementation will depend on the presence of the APR/native
         library and the useOpenSSL attribute of the
         AprLifecycleListener.
         Either JSSE or OpenSSL style configuration may be used regardless of
         the SSLImplementation selected. JSSE style configuration is used below.
    -->
    <!--
    <Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
               maxThreads="150" SSLEnabled="true">
        <SSLHostConfig>
            <Certificate certificateKeystoreFile="conf/localhost-rsa.jks"
                         type="RSA" />
        </SSLHostConfig>
    </Connector>
    -->
    <!-- Define a SSL/TLS HTTP/1.1 Connector on port 8443 with HTTP/2
         This connector uses the APR/native implementation which always uses
         OpenSSL for TLS.
         Either JSSE or OpenSSL style configuration may be used. OpenSSL style
         configuration is used below.
    -->
    <!--
    <Connector port="8443" protocol="org.apache.coyote.http11.Http11AprProtocol"
               maxThreads="150" SSLEnabled="true" >
        <UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" />
        <SSLHostConfig>
            <Certificate certificateKeyFile="conf/localhost-rsa-key.pem"
                         certificateFile="conf/localhost-rsa-cert.pem"
                         certificateChainFile="conf/localhost-rsa-chain.pem"
                         type="RSA" />
        </SSLHostConfig>
    </Connector>
    -->

    <!-- Define an AJP 1.3 Connector on port 8009 -->
    <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />

    <!-- 每个Service只能有一个<Engine>元素 -->
    <Engine name="Catalina" defaultHost="localhost">

      <!--For clustering, please take a look at documentation at:
          /docs/cluster-howto.html  (simple how to)
          /docs/config/cluster.html (reference documentation) -->
      <!--
      <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>
      -->

      <!-- Use the LockOutRealm to prevent attempts to guess user passwords
           via a brute-force attack -->
      <Realm className="org.apache.catalina.realm.LockOutRealm">
        <!-- This Realm uses the UserDatabase configured in the global JNDI
             resources under the key "UserDatabase".  Any edits
             that are performed against this UserDatabase are immediately
             available for use by the Realm.  -->
        <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
               resourceName="UserDatabase"/>
      </Realm>
	  <!-- 默认host配置,有几个域名就配置几个Host,但是这种只能是同一个端口号 -->
      <Host name="localhost"  appBase="webapps" unpackWARs="true" autoDeploy="true">
		 <!-- <Context path="/ref-comet" docBase="D:\work_tomcat\ref-comet"/> -->
        <!-- SingleSignOn valve, share authentication between web applications
             Documentation at: /docs/config/valve.html -->
        <!--
        <Valve className="org.apache.catalina.authenticator.SingleSignOn" />
        -->

        <!-- Tomcat的访问日志,会在logs文件里生成localhost_access_log的访问日志,可以关闭 -->
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="localhost_access_log" suffix=".txt"
               pattern="%h %l %u %t &quot;%r&quot; %s %b" />
      </Host>
    </Engine>
  </Service>
</Server>

7. Tomcat组件及架构

Tomcat组件及架构图

  1. Server:整个Servlet容器,一个Server可以有多个Service
  2. Service:一个Service维护多个Connector和一个Container
  3. Connector:链接器,监听转换Socket请求,将请求交给Container处理,支持不同协议以及不同的I/O方式
  4. Container:表示能够执行客户端请求并返回响应的一类对象,其中有不同级别的容器:Engine、Host、Context、Wrapper
  5. Engine:整个Servler引擎,最高级的容器对象
  6. Host:表示Servlet引擎中的虚拟机,主要与域名有关,一个服务器有多个域名可以使用多个Host
  7. Context:表示ServletContext,一个ServletContext表示一个独立的Web应用
  8. Wrapper:表示Web应用中定义的Servlet
  9. Executor:Tomcat组件间可以共享的线程池

7.1 Connector

Connector在整体架构中的作用:
Connector在整体架构中的作用
Connector用于网络协议与容器的解耦:

  1. Connector 链接器封装底层的网络请求(Socket 请求及相应处理),提供了统一的接口,使 Container 容器与具体的请求协议以及 I/O 方式解耦。
  2. Connector 将 Socket 输入转换成 Request 对象,交给 Container 容器进行处理,处理请求后,Container 通过 Connector 提供的 Response 对象将结果写入输出流。
  3. 无论是 Request 对象还是 Response 对象都没有实现 Servlet 规范对应的接口,Container 会将它们进一步封装成 ServletRequest、ServletResponse。

Connector有3种传输协议:

  1. HTTP:HTTP/1.1协议
  2. AJP协议:主要与Apache HTTP Server集成
  3. HTTP2:HTTP/2.0协议,下一代HTTP协议

Connector有3种I/O方式:

  1. NIO:采用JDK的NIO类库实现
  2. NIO2(AIO):采用JDK1.7的NIO2类库实现
  3. APR:采用APR(Apache可移植运行库)

协议与IO
如何选择协议与IO方式:

  1. org.apache.coyote.http11.Http11NioProtocol:http + NIO的方式
  2. org.apache.coyote.http11.Http11Nio2Protocol:http + NIO2(AIO)的方式
  3. org.apache.coyote.http11.Http11AprProtocol:http + Apr的方式

对于IO选择,要根据业务场景来定:一般高并发场景下,APR 和 NIO2 的性能要优于 NIO 和 BIO:linux 操作系统支持的 NIO2 由于是一个假的,并没有真正实现 AIO,所以一般 linux 上推荐使用 NIO;如果是 APR 的话,需要安装 APR 库,Windows 上默认安装了)。 8.5 的版本默认是 NIO。

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐