小知识,大挑战!本文正在参与“程序员必备小知识”创作活动
tomcat
连接器组件Connect
和socket通信, Http容器
Coyote
- Coyote 封装了底层的⽹络通信(Socket 请求及响应处理)
- Coyote 使Catalina 容器(容器组件)与具体的请求协议及IO操作⽅式完全解耦
- Coyote 将Socket 输⼊转换封装为 Request 对象,进⼀步封装后交由Catalina 容器进⾏处理,处理请求完成后, Catalina 通过Coyote 提供的Response 对象将结果写⼊输出流
- Coyote 负责的是具体协议和IO相关内容
内部组件
- EndPoint EndPoint 是 Coyote 通信端点,即通信监听的接⼝,是具体Socket接收和发送处理器,是对传输层的抽象,因此EndPoint⽤来实现TCP/IP协议的
- Processor Processor 是Coyote 协议处理接⼝ ,Processor⽤来实现HTTP协议, Processor接收来⾃EndPoint的Socket,读取字节流解析成Tomcat Request和Response对象,并通过Adapter将其提交到容器处理, Processor是对应⽤层协议的抽象
- ProtocolHandler Coyote 协议接⼝, 通过Endpoint 和Processor , 实现针对具体协议的处理能⼒。
- Adapter负责将Tomcat Request转成ServletRequest,再调⽤容器
容器组件Container
Servlet 容器
Catalina
一个Catalina实例
一个Server实例
多个Service实例
多个Connector实例和一个Container实例
- Catalina 负责解析Tomcat的配置⽂件(server.xml) , 以此来创建服务器Server组件并进⾏管理
- Server 服务器表示整个Catalina Servlet容器以及其它组件,负责组装并启动Servlet引擎,Tomcat连接器。 Server通过实现Lifecycle接⼝,提供了⼀种优雅的启动和关闭整个系统的⽅式
- Service 服务是Server内部的组件,⼀个Server包含多个Service。它将若⼲个Connector组件绑定到⼀个Container
- Container 容器,负责处理⽤户的servlet请求,并返回对象给web⽤户的模块
Container结构
Container组件下有⼏种具体的组件,分别是Engine、 Host、 Context和Wrapper。这4种组件(容器)是⽗⼦关系。 Tomcat通过⼀种分层的架构,使得Servlet容器具有很好的灵活性
- Engine 表示整个Catalina的Servlet引擎,⽤来管理多个虚拟站点,⼀个Service最多只能有⼀个Engine,但是⼀个引擎可包含多个Host
- Host 代表⼀个虚拟主机,或者说⼀个站点,可以给Tomcat配置多个虚拟主机地址,⽽⼀个虚拟主机下可包含多个Context
- Context 表示⼀个Web应⽤程序, ⼀个Web应⽤可包含多个Wrapper
- Wrapper 表示⼀个Servlet, Wrapper 作为容器中的最底层,不能包含⼦容器配置其实就体现在conf/server.xml中
配置
server.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- Note: A "Server" is not itself a "Container", so you may not
define subcomponents such as "Valves" at this level.
Documentation at /docs/config/server.html
-->
<!-- 关闭服务器的监听端口 shutdown的指令 Server标识org.apache.catalina.Server接口的类 默认org.apache.catalina.core.StandardServer-->
<Server port="8005" shutdown="SHUTDOWN">
<!-- 日志形式输出服务器 操作系统 JVM版本信息-->
<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 -->
<!-- 加载和销毁 APR 如果找不到, 不影响启动-->
<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
<!-- Prevent memory leaks due to use of particular java/javax APIs-->
<!-- 避免JRE内存溢出-->
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
<!-- 全局命名服务-->
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
<!-- Context停止时,重建Executor的线程,避免ThreadLocal内存溢出-->
<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
<!-- Global JNDI resources
Documentation at /docs/jndi-resources-howto.html
-->
<!--全局命名服务-->
<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>
<!-- A "Service" is a collection of one or more "Connectors" that share
a single "Container" Note: A "Service" is not itself a "Container",
so you may not define subcomponents such as "Valves" at this level.
Documentation at /docs/config/service.html
-->
<Service name="Catalina">
<!--The connectors can use a shared executor, you can define one or more named thread pools-->
<!-- 连接器Connector的线程池-->
<!--
threadPriority 从1 到15
<Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
maxThreads="150" minSpareThreads="4"/>
<Executor name="commonThread" namePrefix="thread-exec-"
maxTreads="200" minSpareThreads="100" maxIdleTime="60000"
maxQueueSize="Integer.MAX_SIZE" prestartminSpareThreads="false"
threadPriority="5" className="org.apache.catalina.core.StandardThreadExecutor"/>
-->
<!-- A "Connector" represents an endpoint by which requests are received
and responses are returned. Documentation at :
Java HTTP Connector: /docs/config/http.html
Java AJP Connector: /docs/config/ajp.html
APR (HTTP/AJP) Connector: /docs/apr.html
Define a non-SSL/TLS HTTP/1.1 Connector on port 8080
<Connector port="8080" protocol="HTTP/1.1"
executor="tomcatThreadPool"
connectionTimeout="20000"
redirectPort="8443"
maxThreads="150"
minSpareThreads="100"
acceptCount="1000"
maxConnections="1000"
compression="on"
compressionMinSize="2048"
disableUploadTimeout="true"
URIEncoding="UTF-8"
SSLEnabled="true"
/>
-->
<!-- 连接器 端口号 协议 超时时间 重定向 -->
<Connector port="8080" protocol="HTTP/1.1"
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 an 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 an 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 protocol="AJP/1.3"
address="::1"
port="8009"
redirectPort="8443" />
-->
<!-- An Engine represents the entry point (within Catalina) that processes
every request. The Engine implementation for Tomcat stand alone
analyzes the HTTP headers included with the request, and passes them
on to the appropriate Host (virtual host).
Documentation at /docs/config/engine.html -->
<!-- You should set jvmRoute to support load-balancing via AJP ie :
org.apahce.catalina.Engine
<Engine name="Catalina" defaultHost="localhost" jvmRoute="jvm1">
-->
<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>
<!-- 配置一个虚拟主机
appBase: 目录
unpackWARs: 解压war包
autoDeploy: 自动部署
-->
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true">
<!-- SingleSignOn valve, share authentication between web applications
Documentation at: /docs/config/valve.html -->
<!--
<Valve className="org.apache.catalina.authenticator.SingleSignOn" />
-->
<!-- Access log processes all example.
Documentation at: /docs/config/valve.html
Note: The pattern used is equivalent to using pattern="common" -->
<!--Log-->
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="localhost_access_log" suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
<Context docBase="/USERS/demo" path="/demo" reloadable="false"></Context>
</Host>
</Engine>
</Service>
</Server>
源码
org.apache.catalina.startup.Bootstrap#main
类加载机制
BootStrapClassLoader ExtClassLoader AppClassLoader
Commons ClassLoader
Catalina ClassLoader ShareClassLoader -- WebApp ClassLoader
- 系统类加载器正常情况下加载的是 CLASSPATH 下的类,但是 Tomcat 的启动脚本并未使⽤该变量,⽽是加载tomcat启动的类,⽐如bootstrap.jar,通常在catalina.bat或者catalina.sh中指定位于CATALINA_HOME/bin下
- Common 通⽤类加载器加载Tomcat使⽤以及应⽤通⽤的⼀些类,位于CATALINA_HOME/lib下,⽐如servlet-api.jar
- Catalina ClassLoader ⽤于加载服务器内部可⻅类,这些类应⽤程序不能访问
- Shared ClassLoader ⽤于加载应⽤程序共享类,这些类服务器不会依赖
- Webapp ClassLoader,每个应⽤程序都会有⼀个独⼀⽆⼆的Webapp ClassLoader,他⽤来加载本应⽤程序 /WEB-INF/classes 和 /WEB-INF/lib 下的类。
tomcat 8.5做出了改变 ⾸先从 Bootstrap Classloader加载指定的类 如果未加载到,则从 /WEB-INF/classes加载 如果未加载到,则从 /WEB-INF/lib/*.jar 加载 如果未加载到,则依次从 System、 Common、 Shared 加载(在这最后⼀步,遵从双亲委派机制)
HTTPS
<Connector port="8443"
protocol="org.apache.coyote.http11.Http11NioProtocol" SSLEnabled="true"
maxThreads="150"
scheme="https"
secure="true"
clientAuth="true"
sslProtocol="TLS"
keystoreFile="D:/keys/tomcat.keystore"
keystorePass="123456"
truststoreFile="D:/keys/tomcat.keystore"
truststorePass="123456" />
性能优化
JVM虚拟机优化
catalina.sh
JAVA_OPTS="-server -Xms2048m -Xmx2048m -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m"
JAVA_OPTS="-XX:+UseConcMarkSweepGC "
配置优化
-
线程池调优
-
禁用AJP连接器
-
调整IO模式, 开启APR模式, 从操作系统级别解决异步IO问题, 使用时操作系统要安装APR和Native.
-
动静分离 Nginx +Tomcat
-
禁用DNS查询,设置server.xml文件中的Connector下的enableLookups为false。
其他
-
如何禁止列目录下的文件
web.xml文件中
<init-param> <param-name>listings</param-name> <param-value>false</param-value> </init-param> -
Tomcat的部署方式
- conf目录中,server.xml的host节点中添加context
- 拷贝项目文件到webapps中
- 在conf目录下新建Catalina/localhost目录,目录中新建一个xml文件,xml中内容为部署一中的context内容
- 使用在线后台管理器,上传war文件。 配置conf/tomcat-users.xml文件,然后访问http://localhost:8080/host-manager/html