一、Tomcat 支持四种 IO 线程模型
<Connector port="8080" protocol="HTTP/1.1" />
BIO
:同步阻塞式 IO
,即 Tomcat 使用传统的 java.io.*
进行操作。
- 该模式下每个请求都会创建一个线程,对性能开销大,不适合高并发场景。
- 优点是稳定,适合连接数目小且固定架构。
<Connector port="8080" protocol="org.apache.coyote.http11.Http11Protocol" />
NIO
:同步非阻塞式 IO
,JDK-1.4
之后实现的新 IO
。
- 该模式基于 多路复用选择器,监测连接状态 再 同步通知线程处理,从而达到 非阻塞 的目的。
- 比传统
BIO
能更好的 支持并发性能。 Tomcat-8.0
之后默认采用该模式。
<Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol" />
AIO
:异步非阻塞式 IO
(Aasynchronous I/O),JDK-1.7
之后支持 。
- 与
NIO
不同在于 不需要 多路复用选择器,而是 请求处理线程执行完成 进行 回调通知,已继续执行后续操作。 Tomcat-8.0
之后支持。
<Connector port="8080" protocol="org.apache.coyote.http11.Http11Nio2Protocol" />
APR
:全称是 Apache
可移植运行库(Apache Portable Runtime),是 Apache HTTP
服务器的支持库。
- 可以简单地理解为,
Tomcat
将以 JNI
的形式调用 Apache HTTP
服务器的 核心动态链接库,来处理 文件读取 或 网络传输 操作。 - 使用需要编译安装
APR
库。
<Connector port="8080" protocol="org.apache.coyote.http11.Http11AprProtocol" />
1. BIO
线程模型
- 会受到 客户端阻塞、网络延迟、业务处理较慢,线程数量会增多。
2. NIO
线程模型
- 会受到 业务处理较慢,线程数量会增多。
Accept
线程组:acceptCount
同时接收最大连接(默认:100)。Exec
线程组:maxThreads
最大线程数(Worker
线程)。
二、Tomcat Connector 并发参数
名称 | 描述 |
---|
acceptCount | 等待最大队列(默认:100) |
address | 绑定客户端特定地址(127.0.0.1) |
bufferSize | 每个请求的缓冲区大小(bufferSize * maxThreads) |
compression | 是否启用文档压缩 |
compressableMimeTypes | text/html,text/xml,text/plain |
connectionTimeout | 客户发起链接,到服务端接收为止,中间最大的等待时间 |
connectionUploadTimeout | Upload 情况下连接超时时间 |
disableUploadTimeout | true 表示使用 connectionTimeout |
enableLookups | 为 true 进行 DNS 查询 |
keepAliveTimeout | 当长链接闲置,指定时间主动关闭链接 ,前提是客户端请求头带上这个head"connection"、" keep-alive" |
maxKeepAliveRequests | 最大的长链接数 |
maxHttpHeaderSize | |
maxSpareThreads | BIO 模式下,最多线闲置线程数 |
maxThreads | 最大执行线程数 |
minSpareThreads | BIO 模式下,最小线闲置线程数(默认:10) |
三、Tomcat 类加载机制
- 是用来加载
Class
文件的。 - 它负责将
Class
的字节码形式,转换成内存形式的 Class
对象。 - 字节码可以来自于磁盘文件
*.class
,也可以是 jar
包里的 *.class
,也可以来自远程服务器提供的 字节流。 - 字节码 的本质就是一个 字节数组
[]byte
,它有特定的复杂的内部格式。
JVM
运行实例中,会存在多个 ClassLoader
。
- 不同的
ClassLoader
会从不同的地方加载字节码文件。 - 它可以从不同的 文件目录加载,也可以从不同的
jar
文件中加载,也可以从网络上不同的静态文件服务器来下载字节码再加载。
JVM
里 ClassLoader 的层次结构。
BootstrapClassLoader
(启动类加载器)。
- 负责加载
JVM
运行时核心类。 - 加载
System.getProperty("sun.boot.class.path");
所指定的路径或 jar
包。
ExtensionClassLoader
(扩展类加载器)。
- 负责加载
JVM
扩展类,比如 swing
系列、内置的 js
引擎、xml
解析器 等等。 - 这些库名通常以
javax
开头,它们的 jar
包位于 JAVAHOME/lib/rt.jar
文件中。 - 加载
System.getProperty("java.ext.dirs");
所指定的路径或 jar
包。 - 在使用
Java
运行程序时,也可以指定其搜索路径。
例如:java -Djava.ext.dirs=d:\projects\testproj\classes HelloWorld
。
- 是直接面向用户的加载器,它会加载
ClassPath
环境变量里定义路径中的 jar 包和目录。 - 我们自己编写的代码以及使用的第三方
jar
包通常都是由它来加载的。 - 加载
System.getProperty("java.class.path");
所指定的路径或 jar
包。 - 在使用
Java
运行程序时,也可以加上 -cp
来覆盖原有的 ClassPath
设置。
例如:java -cp ./lavasoft/classes HelloWorld
。
四、Tomcat 类加载顺序
- 在 Tomcat 中,默认是先尝试在
Bootstrap
和 Extension
中进行类型加载。 - 如果加载不到,则在
WebappClassLoader
中进行加载。 - 如果还是找不到,则在
Common
中进行查找。
五、ClassLoader 异常
1. NoClassDefFoundError 找不到类定义错误
- NoClassDefFoundError 的产生,是由于
JVM
或者 类加载器 尝试加载类型的定义,但是该定义却没有找到。 - 换句话说,在编译时 这个类是能够被找到的,但是在执行时 却没有找到。
2. NoSuchMethodError 没有这样的方法错误
NoSuchMethodError
代表这个类型确实存在,但是一个不正确的版本被加载了。
3. ClassCastException 类强制转换异常
ClassCastException
一般出现这种错误都会是在 转型操作时。- 比如:
A a = (A) method();
,很容易判断出来 method()
方法,返回的类型不是类型 A
。