前言
在一个项目中永远离不开tomcat,你对tomcat了解多少呢?对于大多数初级程序员来说对于tomcat的了解可能只有怎么部署tomcat,怎么去运行项目,其实tomcat对于我们开发来说还是很重要的,大多数项目的部署运行都是依赖于tomcat的,所以有必要对tomcat有一个深入的了解,本文就简单地介绍一下tomcat。
❤️浏览器请求流程
正常情况浏览器发送请求到展示出结果需要经过下面步骤:
- 浏览器输入一个地址(http://localhost:8080/test)。
- 地址经过解析后找到对应的服务器,中间经过三次握手与之建立起TCP/IP连接。
- 建立连接后,浏览器开始向服务器发送请求报文。
- 服务器解析请求信息,然后执行对应的服务,生成对应结果。
- 服务器将对应结果发送回浏览器。
- 浏览器解析对应的返回数据呈现在页面上。
❤️Tomcat架构简介
Tomcat是由图中这几部分功能组成的
- Juli: 日志服务,这是tomcat内部自带的日志,根据官网的介绍其是对Apache Commons Logging重命名打包。
- Naming: 命名服务,提供了对JNDI的支持,提供了访问各种命名和服务目录的API,可以直接使用名字访问对象和对象资源的支持。
- JavaEL: EL表达式服务,提供了对于EL表达式的支持,对于以前写过JSP的程序员可能对EL表达式比较了解。
- Jasper: Jsp引擎,提供了对于对JSP页面支持,可以解析JSP语法支持,JSP最终会被解析为.class文件放到work目录。
- Coyote: 连接器,负责与客户端建立连接、发送请求和接受响应。
- Catalina: Servlet容器,Tomcat中工作的核心,负责加载和管理Servlet以及处理Request请求。
Tomcat这些功能组件中最核心的两个组件是Coyote和Catalina。
🤍连接器
连接器是Tomcat对外的接口,其底层封装了Socket的请求和响应处理,可以将Socket输入的内容转换为Request对象,然后交给Servlet容器处理,处理完成后又通过连接器提供的Response对象将结果通过Socket发送回去。
Coyote连接器由下面几部分构成:
- ProtocolHandler: 由EndPoint和Processor组成,主要实现Tomcat对于协议的处理。
- EndPoint:EndPoint用来TCP/IP协议,是Tomcat中用来通信的,负责Socket的接收和发送。
- Processor:Processor用来实现HTTP协议,将EndPoint接收的流读取解析为Request和Response对象。
- Adapter: Tomcat中的适配器,前面Processor发送过来的Request是Tomcat自己定义的Request对象,由适配器转换为Servlet Request对象。
Tomcat支持多种IO模型和协议主要是通过Coyote来实现的。
Tomcat支持的协议:
协议 | 解释 |
---|---|
HTTP 1.1 | 大部分Web应用采用的是HTTP/1.1 访问协议 |
HTTP 2.0 | HTTP2.0是HTTP1的下一代协议,大幅提高了Web性能,Tomcat8.5及之后版本支持 |
AJP | AJP协议用来实现对静态资源的优化以及集群部署 |
Tomcat支持的IO模型:
IO模型 | 解释 |
---|---|
BIO | 阻塞IO,性能非常低,在tomcat8.0之前默认使用BIO |
NIO | 非阻塞IO,tomcat8.0之后默认使用NIO |
AIO | 异步非阻塞IO,tomcat8.0之后开始支持,可以通过配置使用 |
APR | 可移植运行库,使用该方式需要单独安装APR库 |
🤍容器
Catalina是Tomcat中的Servlet容器,Tomcat启动的时候会初始化Servlet容器,Catalina通过加载Server.xml完成其他实例的创建,并且创建和管理一个Server。Server中有多个Service,Service中有多个Connector和一个Container。看一下Tomcat另一个角度的架构图。
来看一下其内部各个部分都是干什么的:
- Server: 整个Servlet容器和其他组件组成的服务器,负责装配启动Servlet引擎和Tomcat连接器。
- Service: Server内部的服务组件,一个Server有多个Service。
- Connector: Tomcat中的连接器。
- Container: 负责处理用户的Servlet请求,并返回对象给Web用户的容器,到这里才是容器部分。
- Engine: 整个Catalina的Servlet引擎,可以管理多个虚拟站点。
- Host: 虚拟站点,一个虚拟站点下面可以有多个应用程序。
- Context: 表示一个应用程序,应用程序下面可以有多个Wrapper。
- Wrapper: 表示一个Servlet,Servlet容器最终管理的就是Servlet。
- Context: 表示一个应用程序,应用程序下面可以有多个Wrapper。
- Host: 虚拟站点,一个虚拟站点下面可以有多个应用程序。
- Engine: 整个Catalina的Servlet引擎,可以管理多个虚拟站点。
❤️Server.xml配置
Tomcat的大体结构已经说完了,下面看一看Tomca的具体配置。
🤍Tomcat的目录结构
Tomcat下有这些目录,其中
- bin是tomcat的脚本文件,启动关闭tomcat在这里面;
- conf是tomcat的配置文件,我们经常修改里面的server.xml来修改端口号;
- lib是tomcat引用的一些jar包,tomcat是基于Java语言编写的;
- logs是tomcat的日志文件,在配置文件中也有对应的配置log目录;
- temp存放的是tomcat的一些临时文件;
- webapps是tomcat运行项目的文件,我们一般把项目放在这下面;
- work是tomcat的工作目录,像一些jsp文件最终会解析为HTML和Java文件就放在了work工作目录。
🤍Server.xml配置
整个tomcat中我们配置最多的可能就是server.xml文件了,上面也说了Tomcat容器是通过server.xml来创建可管理服务的,这个文件在conf目录下面,打开server.xml看一下其中都有哪些配置。
<?xml version="1.0" encoding="UTF-8"?>
从上面的架构图就可以看出来Server是Tomcat的根元素,整个Tomcat就是一个Server,port是监听端口号,shutdown是关闭服务器的指令
<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" />
全局命名服务,前面说到过一个Naming服务
<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服务
<Service name="Catalina">
配置了共享线程池,跟Java中的线程配置差不多
<Executor name="commonThreadPool" 线程池名称
namePrefix="thread-exec-" 线程名称
maxThreads="200" 最大线程数量
minSpareThreads="100" 核心线程数量
maxIdleTime="60000" 线程空闲时间
maxQueueSize="Integer.MAX_VALUE" 队列最大数量
prestartminSpareThreads="false" 是否启动线程池时启动核心线程
threadPriority="5" 线程的优先级
className="org.apache.catalina.core.StandardThreadExecutor"/> 实现的线程池类
连接器标签
<Connector port="8080" <!-- 端口号是对外Socket通信的端口号 -->
protocol="HTTP/1.1" <!-- 配置的访问协议,默认使用HTTP/1.1 -->
connectionTimeout="20000" <!--连接器的等待超时时间,单位毫秒 -->
SSLEnabled="true" <!--开启SSL传输服务 -->
redirectPort="8443" <!--如果用到SSL传输时,会自动将请求定位到该端口 -->
executor="tomcatThreadPool" <!--指定共享线程池的名称 -->
maxThreads="150" <!--配置最大线程数量 -->
minSpareThreads="100" <!--核心线程数量 -->
acceptCount="1000" <!--线程的最大排队数量 -->
maxConnections="1000" <!--最大连接数 -->
compression="on" <!--是否开启压缩 -->
compressionMinSize="2048" <!--压缩内容的最小大小 -->
disableUploadTimeout="true" <!--是否禁用上传超时设置 -->
URIEncoding="UTF-8" <!--URI的字符编码 -->
/>
Servlet引擎,defaultHost是默认虚拟主机名称
<Engine name="Catalina" defaultHost="localhost">
认证体系
<Realm className="org.apache.catalina.realm.LockOutRealm">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase"/>
</Realm>
虚拟主机,这就是为经常输入localhost了,appBase指定内部服务基本路径
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true">
应用程序,docBase是war包相对appBase的部署路径,也可以使用绝对路径
<Context docBase="../webapps2" path="/web1"></Context>
日志配置
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="localhost_access_log" suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
</Host>
</Engine>
</Service>
</Server>
下面咱做个实验,不喜欢用localhost访问系统,改成www.jack.com吧。
这里还需要修改电脑的hosts文件的,否则CDN解析不到www.jack.com是啥
最终使用www.jack.com:8080就打开了tomcat,如果觉得带着8080不好看的话可以将端口号改成80就不用带端口号了。