关于java:为什么Tomcat架构要这么设计这篇文章告诉你答案

0次阅读

共计 9608 个字符,预计需要花费 25 分钟才能阅读完成。

Tomcat 体系架构

Tomcat 我的项目构造

bin 目录

bin 目录次要是用来寄存 tomcat 的命令,次要有两大类,一类是以.sh 结尾的(linux 命令),另一类是以.bat 结尾的(windows 命令)。

很多环境变量的设置都在此处,例如能够设置 JDK 门路、tomcat 门路

  • startup 文件:次要是查看 catalina.bat/sh 执行所需环境,并调用 catalina.bat 批处理文件。启动 tomcat。
  • catalina 文件:真正启动 Tomcat 文件,能够在外面设置 jvm 参数。前面性能调优会重点讲
  • shutdown 文件:敞开 Tomcat
  • 脚本 version.sh、startup.sh、shutdown.sh、configtest.sh 都是对 catalina.sh 的包装,内容大同小异,差别在于性能介绍和调用 catalina.sh 时的参数不同。
  • Version:查看以后 tomcat 的版本号,
  • Configtest:校验 tomcat 配置文件 server.xml 的格局、内容等是否非法、正确。
  • Service:装置 tomcat 服务,可用 net start tomcat 启动

conf 目录

conf 目录次要是用来寄存 tomcat 的一些配置文件。

  • server.xml:能够设置端口号、设置域名或 IP、默认加载的我的项目、申请编码
  • web.xml:能够设置 tomcat 反对的文件类型
  • context.xml:能够用来配置数据源之类的
  • tomcat-users.xml:用来配置管理 tomcat 的用户与权限
  • 在 Catalina 目录下能够设置默认加载的我的项目
server.xml
COPY<?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" />
<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" />
<!-- 全局命名资源,定义了 UserDatabase 的一个 JNDI(java 命名和目录接口),通过 pathname 的文件失去一个用户受权的内存数据库 -->
<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 它蕴含一个 <Engine> 元素, 以及一个或多个 <Connector>, 这些 Connector 元素共享用同一个 Engine 元素 -->
<Service name="Catalina">
<!-- 
         每个 Service 能够有一个或多个连接器 <Connector> 元素,第一个 Connector 元素定义了一个 HTTP Connector, 它通过 8080 端口接管 HTTP 申请; 第二个 Connector 元素定
         义了一个 JD Connector, 它通过 8009 端口接管由其它服务器转发过去的申请.
     -->
<Connector port="8080" protocol="HTTP/1.1"
                connectionTimeout="20000"
                redirectPort="8443" />
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
<!-- 每个 Service 只能有一个 <Engine> 元素 -->
<Engine name="Catalina" defaultHost="localhost">
<Realm className="org.apache.catalina.realm.LockOutRealm">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
                resourceName="UserDatabase"/>
</Realm>
<!-- 默认 host 配置,有几个域名就配置几个 Host,然而这种只能是同一个端口号 -->
<Host name="localhost"  appBase="webapps"
             unpackWARs="true" autoDeploy="true">
       <!-- 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"%r"%s %b" />
</Host>
<Host name="www.hzg.com"  appBase="webapps"
             unpackWARs="true" autoDeploy="true">
<Context path=""docBase="/myweb1" />
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
                prefix="hzg_access_log" suffix=".txt"
                pattern="%h %l %u %t"%r"%s %b" />
</Host>
</Engine>
</Service>
</Server>
patter 解释

无效的日志格局模式能够参见上面内容,如下字符串,其对应的信息由指定的响应内容取代:

  • %a – 近程 IP 地址
  • %A – 本地 IP 地址
  • %b – 发送的字节数,不包含 HTTP 头,或“–”如果没有发送字节
  • %B – 发送的字节数,不包含 HTTP 头
  • %h – 近程主机名
  • %H – 申请协定
  • %l (小写的 L)- 近程逻辑从 identd 的用户名(总是返回’–‘)
  • %m – 申请办法
  • %p – 本地端口
  • %q – 查问字符串(在后面加上一个“?”如果它存在,否则是一个空字符串
  • %r – 第一行的要求
  • %s – 响应的 HTTP 状态代码
  • %S – 用户会话 ID
  • %t – 日期和工夫,在通用日志格局
  • %u – 近程用户身份验证
  • %U – 申请的 URL 门路
  • %v – 本地服务器名
  • %D – 解决申请的工夫(以毫秒为单位)
web.xml

Tomcat 中所有利用默认的部署形容文件,次要定义了根底的 Servlet 和 MIME 映射(mime-mapping 文件类型,其实就是 Tomcat 解决的文件类型), 如果部署的利用中不蕴含 Web.xml,那么 Tomcat 将应用此文件初始化部署形容,反之,Tomcat 会在启动时将默认形容与定义形容配置进行合并。

加载一些 tomcat 内置的 servlet

DefaultServlet 默认的, 加载动态文件 html,js,jpg 等动态文件。

JspServlet 专门解决 jsp。

context.xml

用于自定义所有 Web 利用均须要加载的 Context 配置,如果 Web 利用指定了本人的 context.xml,那么该文件的配置将被笼罩。

context.xml 与 server.xml 中配置 context 的区别

server.xml 是不可动静重加载的资源,服务器一旦启动了当前,要批改这个文件,就得重启服务器能力从新加载。而 context.xml 文件则不然,tomcat 服务器会定时去扫描这个文件。一旦发现文件被批改(工夫戳扭转了),就会主动从新加载这个文件,而不须要重启服务器。

catalina.policy

权限相干 Permission,Tomcat 是跑在 jvm 上的,所以有些默认的权限

tomcat-users.xml

配置 Tomcat 的 server 的 manager 信息

COPY<?xml version="1.0" encoding="UTF-8"?>
<tomcat-users xmlns="http://tomcat.apache.org/xml"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://tomcat.apache.org/xml tomcat-users.xsd"
              version="1.0">
<role rolename="manager-gui"/>
<user username="manager" password="manager" roles="manager-gui"/>
</tomcat-users>
logging.properties

设置 tomcat 日志

管制输入不输入内容到文件,不能阻止生成文件,阻止声文件可用正文掉

lib 目录

lib 目录次要用来寄存 tomcat 运行须要加载的 jar 包。

例如,像连贯数据库的 jdbc 的包咱们能够退出到 lib 目录中来。

Tomcat 的类库,外面是一大堆 jar 文件。如果须要增加 Tomcat 依赖的 jar 文件,能够把它放到这个目录中,当然也能够把利用依赖的 jar 文件放到这个目录中,这个目录中的 jar 所有我的项目都能够共享之,但这样你的利用放到其余 Tomcat 下时就不能再共享这个目录下的 Jar 包了,所以倡议只把 Tomcat 须要的 Jar 包放到这个目录下;

logs 目录

logs 目录用来寄存 tomcat 在运行过程中产生的日志文件,十分重要的是在控制台输入的日志。(清空不会对 tomcat 运行带来影响)

这个目录中都是日志文件,记录了 Tomcat 启动和敞开的信息,如果启动 Tomcat 时有谬误,那么异样也会记录在日志文件中

在 windows 环境中,控制台的输入日志在 catalina.xxxx-xx-xx.log 文件中
​ 在 linux 环境中,控制台的输入日志在 catalina.out 文件中

  • localhost-xxx.log:Web 利用的外部程序日志,倡议保留
  • catalina-xxx.log:控制台日志
  • host-manager.xxx.log:Tomcat 治理页面中的 host-manager 的操作日志,倡议敞开
  • localhost_access_log_xxx.log:用户申请 Tomcat 的拜访日志(这个文件在 conf/server.xml 里配置),倡议敞开

temp 目录

temp 目录用户寄存 tomcat 在运行过程中产生的临时文件。(清空不会对 tomcat 运行带来影响)

webapps 目录

webapps 目录用来寄存应用程序,当 tomcat 启动时会去加载 webapps 目录下的应用程序。能够以文件夹、war 包、jar 包的模式公布利用。

当然,你也能够把应用程序搁置在磁盘的任意地位,在配置文件中映射好就行。

寄存 web 我的项目的目录,其中每个文件夹都是一个我的项目;如果这个目录下曾经存在了目录,那么都是 tomcat 自带的。我的项目。其中 ROOT 是一个非凡的我的项目,在地址栏中没有给出我的项目目录时,对应的就是 ROOT 我的项目。http://localhost:8080/examples,进入示例我的项目。其中 examples 就是我的项目名,即文件夹的名字。

work 目录

work 目录用来寄存 tomcat 在运行时的编译后文件,例如 JSP 编译后的文件。
清空 work 目录,而后重启 tomcat,能够达到革除缓存的作用。

运行时生成的文件,最终运行的文件都在这里。通过 webapps 中的我的项目生成的!能够把这个目录下的内容删除,再次运行时会生再次生成 work 目录。当客户端用户拜访一个 JSP 文件时,Tomcat 会通过 JSP 生成 Java 文件,而后再编译 Java 文件生成 class 文件,生成的 java 和 class 文件都会寄存到这个目录下。

Tomcat 组件及架构

Server

Server 是最顶级的组件,它代表 Tomcat 的运行实例,它主持着整个 Tomcat 的生死大权;

  • 提供了监听器机制,用于在 Tomcat 整个生命周期中对不同工夫进行解决
  • 提供 Tomcat 容器全局的命名资源实现,JNDI
  • 监听某个端口以承受 SHUTDOWN 命令,用于敞开 Tomcat

Service

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

它由一个或者多个 Connector 组成,以及一个 Engine,负责解决所有 Connector 所取得的客户申请。

Connector 组件

链接器:监听转换 Socket 申请,将申请交给 Container 解决,反对不同协定以及不同的 I / O 形式

TOMCAT 有两个典型的 Connector,一个间接侦听来自 browser 的 http 申请,一个侦听来自其它 WebServer 的申请 Coyote Http/1.1 Connector 在端口 8080 处侦听来自客户 browser 的 http 申请 Coyote JK2 Connector 在端口 8009 处侦听来自其它 WebServer(Apache)的 servlet/jsp 代理申请。

Container

示意可能执行客户端申请并返回响应的一类对象,其中有不同级别的容器:Engine、Host、Context、Wrapper

Engine

整个 Servler 引擎,最高级的容器对象

Engine 下能够配置多个虚拟主机 Virtual Host,每个虚拟主机都有一个域名当 Engine 取得一个申请时,它把该申请匹配到某个 Host 上,而后把该申请交给该 Host 来解决 Engine 有一个默认虚拟主机,当申请无奈匹配到任何一个 Host 上的时候,将交给该默认 Host 来解决。

Host

示意 Servlet 引擎中的虚拟机,次要与域名无关,一个服务器有多个域名是能够应用多个 Host

代表一个 Virtual Host,虚拟主机,每个虚拟主机和某个网络域名 Domain Name 相匹配,每个虚拟主机下都能够部署 (deploy) 一个或者多个 Web App,每个 Web App 对应于一个 Context,有一个 Context path 当 Host 取得一个申请时,将把该申请匹配到某个 Context 上,而后把该申请交给该 Context 来解决匹配的办法是“最长匹配”,所以一个 path==””的 Context 将成为该 Host 的默认 Context 所有无奈和其它 Context 的路径名匹配的申请都将最终和该默认 Context 匹配。

Context

用于示意 ServletContext, 一个 ServletContext 示意一个独立的 Web 利用

一个 Context 对应于一个 Web Application,一个 WebApplication 由一个或者多个 Servlet 组成,Context 在创立的时候将依据配置文件 $CATALINA_HOME/conf/web.xml 和 $WEBAPP_HOME/WEB-INF/web.xml 载入 Servlet 类,当 Context 取得申请时,将在本人的映射表 (mapping table) 中寻找相匹配的 Servlet 类。如果找到,则执行该类,取得申请的回应,并返回。

是 Web 利用的形象,Web 利用部署到 Tomcat 后运行时就会转化成 Context 对象;蕴含了各种动态资源、若干 Servlet(Wrapper 容器)以及各种其余动静资源;

  • 蕴含 Listener 组件用以在生命周期中对 Context 相干的事件进行监听;
  • 蕴含 AccessLog 组件以记录拜访日志;
  • 蕴含 Pipeline 组件用以解决申请;
  • 蕴含 Realm 组件用以提供平安权限性能;
  • 蕴含 Loader 组件用以加载 Web 利用的资源,保障不同 Web 利用之间的资源隔离;
  • 蕴含 Manager 组件用以治理 Web 容器的会话,包含保护会话的生成、更新和销毁;
  • 蕴含 NamingResource 组件将 Tomcat 配置文件的 server.xml 和 Web 利用的 context.xml 资源和属性映射到内存中;

Wrapper

用于示意 Web 利用中定义的 Servlet

对应的是 Servlet;蕴含 Web 利用开发罕用的 Servlet 组件;蕴含 ServletPool 组件用以寄存 Servlet 对象,当 Web 利用的 Servlet 实现了 SingleThreadModel 接口时则会再 Wrapper 中产生一个 Servlet 对象池,线程执行时,需先从对象池中获取到一个 Servlet 对象,ServletPool 组件能保障 Servlet 对象的线程平安;蕴含 Pipeline 组件用以解决申请。

咱们从性能的角度将 Tomcat 源代码分成 5 个子模块,它们别离是:

  1. Jsper 子模块:这个子模块负责 jsp 页面的解析、jsp 属性的验证,同时也负责将 jsp 页面动静转换为 java 代码并编译成 class 文件。在 Tomcat 源代码中,但凡属于 org.apache.jasper 包及其子包中的源代码都属于这个子模块;
  2. Servlet 和 Jsp 标准的实现模块:这个子模块的源代码属于 javax.servlet 包及其子包,如咱们十分相熟的 javax.servlet.Servlet 接口、javax.servet.http.HttpServlet 类及 javax.servlet.jsp.HttpJspPage 就位于这个子模块中;
  3. Catalina 子模块:这个子模块蕴含了所有以 org.apache.catalina 结尾的 java 源代码。该子模块的工作是标准了 Tomcat 的总体架构,定义了 Server、Service、Host、Connector、Context、Session 及 Cluster 等要害组件及这些组件的实现,这个子模块大量使用了 Composite 设计模式。同时也标准了 Catalina 的启动及进行等事件的执行流程。从代码浏览的角度看,这个子模块应该是咱们浏览和学习的重点。
  4. Connectors 子模块:如果说下面三个子模块实现了 Tomcat 应用服务器的话,那么这个子模块就是 Web 服务器的实现。所谓连接器 (Connector) 就是一个连贯客户和应用服务器的桥梁,它接管用户的申请,并把用户申请包装成规范的 Http 申请(蕴含协定名称,申请头 Head,申请办法是 Get 还是 Post 等等)。同时,这个子模块还依照规范的 Http 协定,负责给客户端发送响应页面,比方在申请页面未发现时,connector 就会给客户端浏览器发送规范的 Http 404 谬误响应页面。
  5. Resource 子模块:这个子模块蕴含一些资源文件,如 Server.xml 及 Web.xml 配置文件。严格说来,这个子模块不蕴含 java 源代码,然而它还是 Tomcat 编译运行所必须的。

Executor

Tomcat 组件间能够共享的线程池

Tomcat 的并发,提供了 Executor 接口来示意一个能够在组件间共享的线程池。该接口同样继承 LifeCycle 接口

共享范畴:Executor 由 Service 保护,因而同一个 Service 中的组件能够共享一个线程池

Tomcat 的外围组件

  • 解耦:网络协议与容器的解耦。
  • Connector:链接器封装了底层的网络申请(Socket 申请及相应解决), 提供了对立的接口,使 Container 容器与具体的申请协定以及 I / O 形式解耦。
  • Connector:将 Socket 输出转换成 Request 对象,交给 Container 容器进行解决,解决申请后,Container 通过 Connector 提供的 Response 对象将后果写入输入流。

因为无论是 Request 对象还是 Response 对象都没有实现 Servlet 标准对应的接口,Container 会将它们进一步分装成 ServletRequest 和 ServletResponse.

Tomcat 的链接器

AJP 次要是用于 Web 服务器与 Tomcat 服务器集成,AJP 采纳二进制传输可读性文本,应用放弃持久性的 TCP 链接,使得 AJP 占用更少的带宽,并且链接开销要小得多,然而因为 AJP 采纳长久化链接,因而无效的连接数较 HTTP 要更多。

对于 I / 0 抉择,要依据业务场景来定,个别高并发场景下,APR 和 NIO2 的性能要优于 NIO 和 BIO,(linux 操作系统反对的 NIO2 因为是一个假的,并没有真正实现 AIO,所以个别 linux 上举荐应用 NIO,如果是 APR 的话,须要装置 APR 库,而 Windows 上默认装置了),所以在 8.5 的版本中默认是 NIO。

Tomcat 运行流程

假如来自客户的申请为 http://localhost:8080/test/index.jsp

  1. 申请被发送到本机端口 8080,被在那里侦听的 Coyote HTTP/1.1 Connector 取得
  2. Connector 把该申请交给它所在的 Service 的 Engine 来解决,并期待 Engine 的回应
  3. Engine 取得申请 localhost:8080/test/index.jsp,匹配它所有虚拟主机 Host
  4. Engine 匹配到名为 localhost 的 Host(即便匹配不到也把申请交给该 Host 解决,因为该 Host 被定义为该 Engine 的默认主机)
  5. localhost Host 取得申请 /test/index.jsp,匹配它所领有的所有 Context
  6. Host 匹配到门路为 /test 的 Context(如果匹配不到就把该申请交给路径名为””的 Context 去解决)
  7. path=”/test”的 Context 取得申请 /index.jsp,在它的 mapping table 中寻找对应的 servlet
  8. Context 匹配到 URL PATTERN 为 *.jsp 的 servlet,对应于 JspServlet 类
  9. 结构 HttpServletRequest 对象和 HttpServletResponse 对象,作为参数调用 JspServlet 的 doGet 或 doPost 办法
  10. Context 把执行完了之后的 HttpServletResponse 对象返回给 Host
  11. Host 把 HttpServletResponse 对象返回给 Engine
  12. Engine 把 HttpServletResponse 对象返回给 Connector
  13. Connector 把 HttpServletResponse 对象返回给客户 browser

本文由 传智教育博学谷狂野架构师 教研团队公布。

如果本文对您有帮忙,欢送 关注 点赞 ;如果您有任何倡议也可 留言评论 私信,您的反对是我保持创作的能源。

转载请注明出处!

正文完
 0