Tomcat 体系架构

Tomcat 体系架构

  • 什么是Web服务器?
    • Web服务器的定义
    • Web服务器的特点
  • 什么是Tomcat
  • Tomcat版本介绍
    • 8.5版本特点
  • Tomcat启动方式
  • Tomcat项目部署
    • 隐式部署
    • 显式部署
      • 添加context元素
      • 创建xml文件
    • 三种方式比较
  • Tomcat目录结构
    • bin
    • config
    • webapps
    • lib
  • Tomcat组件及架构
    • Server
      • Service
        • Connector
        • Container
        • Executor
  • Tomcat处理一个HTTP请求的过程
  • Connector配置详解
  • 连接数问题

什么是Web服务器?

Web服务器的定义

没有标准定义。一般认为,Web服务器一般指网站服务器,是指驻留于因特网上某种类型计算机的程序,提供网上信息浏览服务。
Tomcat 体系架构_第1张图片

Web服务器的特点

  1. 服务器是一种被动程序:只有当Internet上运行其他计算机中的浏览器发出的请求时,服务器才会响应。
  2. 服务器一般使用HTTP(超文本传输协议)与客户机浏览器进行信息交流,这就是人们常把它们称为HTTP服务器的原因。
  3. Web服务器不仅能够存储信息,还能在用户通过Web浏览器提供的信息的基础上运行脚本和程序。

什么是Tomcat

Tomcat是一款开源轻量级Web应用服务器,是一款优秀的Servlet容器实现。
Servlet(Server Applet)是Java Servlet的简称,称为小服务程序或服务连接器,用Java编写的服务器端程序,具有独立于平台和协议的特性,主要功能在于交互式地浏览和生成数据,生成动态Web内容。
Servlet严格来讲是指Java语言实现的一个接口,一般情况下我们说的Servlet是指任何实现了这个Servlet接口的类。
Tomcat 体系架构_第2张图片

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

典型的Servlet的处理流程:

  1. 第一个到达服务器的 HTTP 请求被委派到 Servlet 容器。
  2. Servlet 容器在调用 service() 方法之前加载 Servlet。
  3. 然后 Servlet 容器处理由多个线程产生的多个请求,每个线程执行一个单一的 Servlet 实例的 service() 方法。

Tomcat版本介绍

Tomcat 体系架构_第3张图片
Servlet 2.X:项目目录结构必须要有WEB-INF,web.xml等文件夹和文件,在web.xml中配置servlet,filter,listener,以web.xml为java web项目的统一入口
Servlet 3.X:项目中可以不需要WEB-INF,web.xml等文件夹和文件,在没有web.xml文件的情况下,通过注解实现servlet,filter, listener的声明,当使用注解时,容器自动进行扫描。

同时Tomcat8.5进行了大量的代码重构,对比与7.0的版本,也符合Tomcat未来的代码架构体系。但是Tomcat的核心和主体架构还是一直保持这样的。

8.5版本特点

  • 支持Servlet3.1
  • 默认采用NIO,移除BIO
  • 支持NIO2(AIO)
  • 支持HTTP 2.0协议
  • 默认采用异步日志处理

Tomcat启动方式

  • 一般启动
    Windows下:startup.bat
    Linux下:startup.sh

  • IDE中启动

  • 嵌入式启动
    启动SpringBoot

  • Debug启动
    在项目发布后,我们有时候需要对基于生产环境部署的应用进行调试,以解决在开发环境无法重现的BUG。这时我们就需要用到应用服务器的远程调试功能,这个主要是基于JDK提供的JPDA(Java Platform Debugger Architecture,Java平台调试体系结构)。

Tomcat项目部署

隐式部署

直接丢文件夹、war、jar到webapps目录,tomcat会根据文件夹名称自动生成虚拟路径,简单,但是需要重启Tomcat服务器,包括要修改端口和访问路径的也需要重启。

显式部署

添加context元素

config/server.xml中的Host加入一个Context(指定路径和文件地址),例如:



即"/index"这个虚拟路径映射到了"F:\work_space\xxxx"目录下(war会解压成文件),修改完servler.xml需要重启tomcat 服务器。

创建xml文件

conf/Catalina/localhost中创建xml文件,访问路径为文件名,例如:
在localhost目录下新建demo.xml,内容为:

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

三种方式比较

  • 隐式部署:可以很快部署,需要人手动移动Web应用到webapps下,在实际操作中不是很人性化
  • 添加context元素 : 配置速度快,需要配置两个路径,如果path为空字符串,则为缺省配置,每次修改server.xml文件后都要重新启动Tomcat服务器,重新部署。
  • 创建xml文件::服务器后台会自动部署,修改一次后台部署一次,不用重复启动Tomcat服务器,该方式显得更为智能化。

Tomcat目录结构

Tomcat 体系架构_第4张图片

bin

  • startup,主要是检查 catalina 的执行所需环境,并调用 catalina,启动 tomcat。

  • catalina,真正启动 tomcat,可以在里面设置JVM参数。

  • shutdown,关闭 tomcat。

  • version:查看当前tomcat的版本号,

  • configtest:校验tomcat配置文件server.xml的格式、内容等是否合法、正确。

  • service:安装tomcat服务,可用net start tomcat 启动

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

config

  • server.xml



<Server port="8005" shutdown="SHUTDOWN">

<Listener className="org.apache.catalina.startup.VersionLoggerListener" />
<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />

<GlobalNamingResources>
<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 name="Catalina">

<Connector port="8080" protocol="HTTP/1.1"
                connectionTimeout="20000"
                redirectPort="8443" />
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />

<Engine name="Catalina" defaultHost="localhost">
<Realm className="org.apache.catalina.realm.LockOutRealm">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
                resourceName="UserDatabase"/>
Realm>

<Host name="localhost"  appBase="webapps"
             unpackWARs="true" autoDeploy="true">
       

Host>
Engine>
Service>
Server>

  • web.xml
    Tomcat中所有应用默认的部署描述文件,主要定义了基础的Servlet和MIME(Multipurpose Internet Mail Extensions)映射(mime-mapping 文件类型,其实就是Tomcat处理的文件类型),如果部署的应用中不包含web.xml,那么Tomcat将使用此文件初始化部署描述,反之,Tomcat会在启动时将默认描述与定义描述配置进行合并。
    加载一些tomcat内置的servlet:
    Tomcat 体系架构_第5张图片
    DefaultServlet默认的,加载静态文件 html,js,jpg等静态文件。
    Tomcat 体系架构_第6张图片
    JspServlet专门处理jsp。
  • context.xml
    用于自定义所有Web应用均需要加载的Context配置,如果Web应用指定了自己的context.xml,那么该文件的配置将被覆盖。
    Tomcat 体系架构_第7张图片
    context.xml 与 server.xml中配置 context 的区别
    server.xml是不可动态重加载的资源,服务器一旦启动了以后,要修改这个文件,就得重启服务器才能重新加载。而context.xml文件则不然,Tomcat服务器会定时去扫描这个文件。一旦发现文件被修改(时间戳改变了),就会自动重新加载这个文件,而不需要重启服务器。
  • catalina.policy
    权限相关 Permission ,Tomcat是跑在JVM上的,所以有些默认的权限
  • tomcat-users.xml
    配置Tomcat的server的manager信息
    Tomcat 体系架构_第8张图片
  • logging.properties
    设置Tomcat日志。

webapps

存放web项目的目录,其中每个文件夹都是一个项目。
Tomcat自带一些项目。其中ROOT是一个特殊的项目,在地址栏中没有给出项目目录时,对应的就是ROOT项目。http://localhost:8080/examples,进入示例项目。

lib

Tomcat的类库。如果需要添加Tomcat依赖的jar文件,可以把它放到这个目录中。

  • work
    运行时生成的文件,最终运行的文件都在这里。通过webapps中的项目生成的。可以把这个目录下的内容删除,再次运行时会生再次生成work目录。当客户端用户访问一个JSP文件时,Tomcat会通过JSP生成Java文件,然后再编译Java文件生成class文件,生成的java和class文件都会存放到这个目录下。
  • temp
    存放Tomcat的临时文件,这个目录下的东西可以在停止Tomcat后删除。
  • logs
    这个目录中都是日志文件,记录了Tomcat启动和关闭的信息,如果启动Tomcat时有错误,那么异常也会记录在日志文件中。
    localhost-xxx.log:Web应用的内部程序日志,建议保留
    catalina-xxx.log:控制台日志
    host-manager.xxx.log:Tomcat管理页面中的host-manager的操作日志,建议关闭
    localhost_access_log_xxx.log:用户请求Tomcat的访问日志(这个文件在conf/server.xml里配置),建议关闭

Tomcat组件及架构

Tomcat 体系架构_第9张图片

Server

Server是最顶级的组件,它代表Tomcat的运行实例,它掌管着整个Tomcat的生死大权(与上面的server.xml对应)。

  • 提供了监听器机制,用于在Tomcat整个生命周期中对不同时间进行处理
  • 提供Tomcat容器全局的命名资源实现,JNDI
  • 监听某个端口以接受SHUTDOWN命令,用于关闭Tomcat

Service

一个概念,一个Service维护多个Connector和一个Container

Connector

链接器:监听转换Socket请求,将请求交给Container处理,支持不同协议以及不同的I/O方式。
Connector链接器封装了底层的网络请求(Socket请求及相应处理),提供了统一的接口,使Container容器与具体的请求协议以及I/O方式解耦
Connector将Socket输入转换成Request对象,交给Container容器进行处理。处理请求后,Container通过Connector提供的Response对象将结果写入输出流。
因为无论是Request对象还是Response对象都没有实现Servlet规范对应的接口,Container会将它们进一步分装成ServletRequest和ServletResponse。
Tomcat 体系架构_第10张图片

Container

在这里插入图片描述
表示能够执行客户端请求并返回响应的一类对象,其中有不同级别的容器:Engine、Host、Context、Wrapper

  • Engine
    整个Servler引擎,最高级的容器对象
    • Host
      表示Servlet引擎中的虚拟机,主要与域名有关,一个服务器有多个域名是可以使用多个Host
      • Context
        用于表示ServletContext,一个ServletContext表示一个独立的Web应用
        • Wrapper
          用于表示Web应用中定义的Servlet

Executor

Tomcat组件间可以共享的线程池

Tomcat处理一个HTTP请求的过程

用户点击网页内容,请求被发送到本机端口8080,被在那里监听的Coyote HTTP/1.1 Connector获得。

Connector把该请求交给它所在的Service的Engine来处理,并等待Engine的回应。

Engine获得请求localhost/test/index.jsp,匹配所有的虚拟主机Host。

Engine匹配到名为localhost的Host(即使匹配不到也把请求交给该Host处理,因为该Host被定义为该Engine的默认主机),名为localhost的Host获得请求/test/index.jsp,匹配它所拥有的所有的Context。Host匹配到路径为/test的Context(如果匹配不到就把该请求交给路径名为“ ”的Context去处理)。
path=“/test”的Context获得请求/index.jsp,在它的mapping table中寻找出对应的Servlet。Context匹配到URL PATTERN为*.jsp的Servlet,对应于JspServlet类。

构造HttpServletRequest对象和HttpServletResponse对象,作为参数调用JspServlet的doGet()或doPost().执行业务逻辑、数据存储等程序。

Context把执行完之后的HttpServletResponse对象返回给Host。

Host把HttpServletResponse对象返回给Engine。

Engine把HttpServletResponse对象返回Connector。

Connector把HttpServletResponse对象返回给客户Browser。

Connector配置详解

以下是server.xml中的一段:

<Connector port="8080" protocol="HTTP/1.1"
                connectionTimeout="20000"
                redirectPort="8443" />
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />

什么是AJP?

Tomcat最主要的功能是提供Servlet/JSP容器。但在对静态资源(如HTML文件或图像文件)的处理速度,以及提供的Web服务器管理功能方面都不如其他专业的HTTP服务器,如IIS和Apache服务器。
因此在实际应用中,常常把Tomcat与其他HTTP服务器集成。对于不支持Servlet/JSP的HTTP服务器,可以通过Tomcat服务器来运行Servlet/JSP组件。
AJP链接器可以让Tomcat通过AJP协议和另一个web容器进行交互。

HTTP/1.1下配置IO
对于I/0选择,要根据业务场景来定。一般高并发场景下,APR和AIO的性能要优于NIO,(linux操作系统并没有真正实现AIO,所以一般linux上推荐使用NIO。如果是APR的话,需要安装APR库,而Windows上默认安装了)。

APR(Apache Portable Runtime):

  • NIO(默认):
<Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol"
                connectionTimeout="20000"
                redirectPort="8443" />
  • AIO(Windows推荐):
<Connector port="8080" protocol="org.apache.coyote.http11.Http11Nio2Protocol"
                connectionTimeout="20000"
                redirectPort="8443" />

在这里插入图片描述

使用线程池:
server.xml 已经写好了如何配置,只需要取消注释就好了。

<Connector executor="tomcatThreadPool"
               port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" /> 
    
     <Connector port="8443" protocol="org.apache.coyote.http11.Http11Nio2Protocol"
               maxThreads="150" >      
    Connector> 
    

在这里插入图片描述

  • APR:
    server.xml 已经写好了如何配置,只需要取消注释就好了。
<Connector executor="tomcatThreadPool"
               port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" /> 
<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>
    

Linux如果安装了apr和native,Tomcat直接启动就支持APR。(安装方法:http://my.oschina.net/lsw90/blog/181161)

连接数问题

NIO:
最大连接数:10000
线程池:200
队列长度:100

1个线程 Acceptor 负责接收连接 Channel 到 accept 队列。2个线程 Poller 负责轮询。轮询到就绪的读/写创建 SocketProcessor 交给线程池 Executor 去执行。在 Executor 的线程中,会完成从 socket 中读取 HttpRequest 解析成 HttpServletRequest 对象,分派到相应的 servlet 并完成逻辑,然后将 Response 通过 socket 发回 client。在从 socket 中读数据和往 socket中写数据的过程,并没有像典型的非阻塞的 NIO 的那样,注册 OP_READ 或 OP_WRITE 事件到主 Selector,而是直接通过 socket 完成读写,这时是阻塞完成的。

你可能感兴趣的:(Tomcat 体系架构)