Tomcat启动过程分析
Tomcat默认server.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<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" />
<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">
<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>
Tomcat只是一个工具,为我们提供一个以war包方式运行web程序的环境而已
server.xml文件是Tomcat的核心文件之一
1.启动Bootstrap
volatile修饰是为了启动唯一的Bootstrap
public final class Bootstrap {
//volatile修饰的静态对象
private static volatile Bootstrap daemon = null;
}
main()
创建Bootstrap对象,并通过初始命令"start"来启动Tomcat
//BootStrap.main()
if (daemon == null) {
Bootstrap bootstrap = new Bootstrap();
......
bootstrap.init();//通过反射创建Catalina对象
......
daemon = bootstrap;
}
......
String command = "start";
......
daemon.start(); //通过反射调用Catalina的start方法
//Bootstrap.start()
public void start() throws Exception {
if (catalinaDaemon == null) {
init();//bootstrap的初始化
}
//反射执行Catalina的start方法,执行
Method method = catalinaDaemon.getClass().getMethod("start", (Class[]) null);
method.invoke(catalinaDaemon, (Object[]) null);
}
综上:
1.Tomcat的启动入口为Bootstrap的Main方法
2.在Main方法中生成Bootstrap对象,Catalina对象
2.Catalina是Tomcat的一个命令程序,Tomcat的启动与关闭就是对bootstrap和catalina对象的创建和销毁过程
2.启动Catalina
在上面Bootstrap的启动过程中会生成Catalina并通过反射调用Catalina的start方法
//Catalina.start()
public void start() {
......
if (getServer() == null) {
load();//加载server.xml文件并创建server
}
//server的初始化
getServer().start();
......
}
3. server.xml文件的加载与解析
在Catalina的start()方法中通过load()方法加载server.xml文件
//Catalina.load()
public void load() {
......
parseServerXml(true); //加载并解析server.xml文件,会创建server,service等组件
Server s = getServer();
if (s == null) {
return;
}
//server赋值
getServer().setCatalina(this);
getServer().setCatalinaHome(Bootstrap.getCatalinaHomeFile());
getServer().setCatalinaBase(Bootstrap.getCatalinaBaseFile());
......
// Start the new server
try {
//server初始化
getServer().init();
} ......
}
server.xml文件的加载解析过程
protected void parseServerXml(boolean start) {
......
if (serverXml != null) {
serverXml.load(this);
} else {
try (ConfigurationSource.Resource resource = ConfigFileLoader.getSource().getServerXml()) {
// Create and execute our Digester
Digester digester = start ? createStartDigester() : createStopDigester();
InputStream inputStream = resource.getInputStream(); //server.xml流文件
InputSource inputSource = new InputSource(resource.getURI().toURL().toString());
inputSource.setByteStream(inputStream);
digester.push(this);
......
}
}
创建Digester,设置规则,然后进行解析
在server.xml的解析过程中会创建server,service等组件
protected Digester createStartDigester() {
// Initialize the digester
Digester digester = new Digester();
digester.setValidating(false);
digester.setRulesValidation(true);
Map<Class<?>, List<String>> fakeAttributes = new HashMap<>();
// Ignore className on all elements
List<String> objectAttrs = new ArrayList<>();
objectAttrs.add("className");
fakeAttributes.put(Object.class, objectAttrs);
// Ignore attribute added by Eclipse for its internal tracking
List<String> contextAttrs = new ArrayList<>();
contextAttrs.add("source");
fakeAttributes.put(StandardContext.class, contextAttrs);
// Ignore Connector attribute used internally but set on Server
List<String> connectorAttrs = new ArrayList<>();
connectorAttrs.add("portOffset");
fakeAttributes.put(Connector.class, connectorAttrs);
digester.setFakeAttributes(fakeAttributes);
digester.setUseContextClassLoader(true);
//创建server
digester.addObjectCreate("Server",
"org.apache.catalina.core.StandardServer",
"className");
digester.addSetProperties("Server");
digester.addSetNext("Server",
"setServer",
"org.apache.catalina.Server");
//全局命名
digester.addObjectCreate("Server/GlobalNamingResources",
"org.apache.catalina.deploy.NamingResourcesImpl");
digester.addSetProperties("Server/GlobalNamingResources");
digester.addSetNext("Server/GlobalNamingResources",
"setGlobalNamingResources",
"org.apache.catalina.deploy.NamingResourcesImpl");
//server生命周期监听器
digester.addRule("Server/Listener",
new ListenerCreateRule(null, "className"));
digester.addSetProperties("Server/Listener");
digester.addSetNext("Server/Listener",
"addLifecycleListener",
"org.apache.catalina.LifecycleListener");
//创建service,在server组件中添加service属性
digester.addObjectCreate("Server/Service",
"org.apache.catalina.core.StandardService",
"className");
digester.addSetProperties("Server/Service");
digester.addSetNext("Server/Service",
"addService",
"org.apache.catalina.Service");
//为service添加监听器
digester.addObjectCreate("Server/Service/Listener",
null, // MUST be specified in the element
"className");
digester.addSetProperties("Server/Service/Listener");
digester.addSetNext("Server/Service/Listener",
"addLifecycleListener",
"org.apache.catalina.LifecycleListener");
//Executor,共享executor的级别为service,默认情况下不开启
digester.addObjectCreate("Server/Service/Executor",
"org.apache.catalina.core.StandardThreadExecutor",
"className");
digester.addSetProperties("Server/Service/Executor");
digester.addSetNext("Server/Service/Executor",
"addExecutor",
"org.apache.catalina.Executor");
digester.addRule("Server/Service/Connector",
new ConnectorCreateRule());
digester.addSetProperties("Server/Service/Connector",
new String[]{"executor", "sslImplementationName", "protocol"});
digester.addSetNext("Server/Service/Connector",
"addConnector",
"org.apache.catalina.connector.Connector");
digester.addRule("Server/Service/Connector", new AddPortOffsetRule());
digester.addObjectCreate("Server/Service/Connector/SSLHostConfig",
"org.apache.tomcat.util.net.SSLHostConfig");
digester.addSetProperties("Server/Service/Connector/SSLHostConfig");
digester.addSetNext("Server/Service/Connector/SSLHostConfig",
"addSslHostConfig",
"org.apache.tomcat.util.net.SSLHostConfig");
digester.addRule("Server/Service/Connector/SSLHostConfig/Certificate",
new CertificateCreateRule());
digester.addSetProperties("Server/Service/Connector/SSLHostConfig/Certificate", new String[]{"type"});
digester.addSetNext("Server/Service/Connector/SSLHostConfig/Certificate",
"addCertificate",
"org.apache.tomcat.util.net.SSLHostConfigCertificate");
digester.addObjectCreate("Server/Service/Connector/SSLHostConfig/OpenSSLConf",
"org.apache.tomcat.util.net.openssl.OpenSSLConf");
digester.addSetProperties("Server/Service/Connector/SSLHostConfig/OpenSSLConf");
digester.addSetNext("Server/Service/Connector/SSLHostConfig/OpenSSLConf",
"setOpenSslConf",
"org.apache.tomcat.util.net.openssl.OpenSSLConf");
digester.addObjectCreate("Server/Service/Connector/SSLHostConfig/OpenSSLConf/OpenSSLConfCmd",
"org.apache.tomcat.util.net.openssl.OpenSSLConfCmd");
digester.addSetProperties("Server/Service/Connector/SSLHostConfig/OpenSSLConf/OpenSSLConfCmd");
digester.addSetNext("Server/Service/Connector/SSLHostConfig/OpenSSLConf/OpenSSLConfCmd",
"addCmd",
"org.apache.tomcat.util.net.openssl.OpenSSLConfCmd");
digester.addObjectCreate("Server/Service/Connector/Listener",
null, // MUST be specified in the element
"className");
digester.addSetProperties("Server/Service/Connector/Listener");
digester.addSetNext("Server/Service/Connector/Listener",
"addLifecycleListener",
"org.apache.catalina.LifecycleListener");
digester.addObjectCreate("Server/Service/Connector/UpgradeProtocol",
null, // MUST be specified in the element
"className");
digester.addSetProperties("Server/Service/Connector/UpgradeProtocol");
digester.addSetNext("Server/Service/Connector/UpgradeProtocol",
"addUpgradeProtocol",
"org.apache.coyote.UpgradeProtocol");
// Add RuleSets for nested elements
digester.addRuleSet(new NamingRuleSet("Server/GlobalNamingResources/"));
digester.addRuleSet(new EngineRuleSet("Server/Service/"));
digester.addRuleSet(new HostRuleSet("Server/Service/Engine/"));
digester.addRuleSet(new ContextRuleSet("Server/Service/Engine/Host/"));
addClusterRuleSet(digester, "Server/Service/Engine/Host/Cluster/");
digester.addRuleSet(new NamingRuleSet("Server/Service/Engine/Host/Context/"));
// When the 'engine' is found, set the parentClassLoader.
digester.addRule("Server/Service/Engine",
new SetParentClassLoaderRule(parentClassLoader));
addClusterRuleSet(digester, "Server/Service/Engine/Cluster/");
return digester;
}
4.启动Server
解析server.xml文件过程中根据规则创建server组件,为Server组件添加Service组件
//StandardServer.addService()
@Override
public void addService(Service service) {
service.setServer(this);
synchronized (servicesLock) {
Service results[] = new Service[services.length + 1];
System.arraycopy(services, 0, results, 0, services.length);
results[services.length] = service;
services = results;
......
service.start(); //启动service
......
5.启动Service
通过生命周期方法start()---->startInternal() 初始化组件
//standardService
protected void startInternal() throws LifecycleException {
if(log.isInfoEnabled())
log.info(sm.getString("standardService.start.name", this.name));
setState(LifecycleState.STARTING);
//初始化engine
if (engine != null) {
synchronized (engine) {
engine.start();
}
}
//初始化executor
synchronized (executors) {
for (Executor executor: executors) {
executor.start();
}
}
//启动mapperLinstener
mapperListener.start();
//启动connectors
synchronized (connectorsLock) {
for (Connector connector: connectors) {
// If it has already failed, don't try and start it
if (connector.getState() != LifecycleState.FAILED) {
connector.start();
}
}
}
}
service组件在初始化过程中会初始化engin,Executor,Connector等组件,这些组件都是在解析server.xml文件时添加的
6.Engine
7.启动Connector
Connector是Tomcat的连接器,默认使用Http协议
public class Connector extends LifecycleMBeanBase {
//默认http1.1协议
public Connector() {
this("org.apache.coyote.http11.Http11NioProtocol");
}
......
public Connector(String protocol) {
......
ProtocolHandler p = null;
try {
p = ProtocolHandler.create(protocol, apr);//创建protocolhandler
......
}
}
startInternal()
启动protocolHandler
try {
protocolHandler.start();
}
8. 启动ProtocolHandler
ProtocolHandler是负责处理请求的,一般情况下处理Http请求,因此默认使用Http协议
AbstractProtocol
public abstract class AbstractProtocol<S> implements ProtocolHandler,
MBeanRegistration {
//处理请求之前需要先监听请求,Endpoint负责绑定请求并进行监听
private final AbstractEndpoint<S,?> endpoint;
//构造方法
public AbstractHttp11Protocol(AbstractEndpoint<S,?> endpoint) {
super(endpoint);
setConnectionTimeout(Constants.DEFAULT_CONNECTION_TIMEOUT);
ConnectionHandler<S> cHandler = new ConnectionHandler<>(this);
setHandler(cHandler);
//NioEndpoint设置protocelHandler
getEndpoint().setHandler(cHandler);
}
protocolHandler.start()
protocolHandler通过endpoint监听http请求,初始endpoint
//AbstractProtocol.start()
public void start() throws Exception {
if (getLog().isInfoEnabled()) {
getLog().info(sm.getString("abstractProtocolHandler.start", getName()));
logPortOffset();
}
//初始化endPoint
endpoint.start();
monitorFuture = getUtilityExecutor().scheduleWithFixedDelay(
new Runnable() {
@Override
public void run() {
if (!isPaused()) {
startAsyncTimeout();
}
}
}, 0, 60, TimeUnit.SECONDS);
}
9.AbstractEndpoint
Endpoint负责监听Socket,在监听之前先初始化并进行与socket绑定
start()
public final void start() throws Exception {
if (bindState == BindState.UNBOUND) {//未绑定状态
bindWithCleanup();
bindState = BindState.BOUND_ON_START;
}
startInternal();//初始化操作,由具体子类实现
}
10. 启动NioEndpoint
此处有三个组件:分别是Poller,PollerEvent,Acceptor
启动NioEndpoint,设置最大连接数,开启线程监听socket等
//NioEndpoint
@Override
public void startInternal() throws Exception {
if (!running) {
running = true;
paused = false;
......
// Create worker collection
if (getExecutor() == null) {
createExecutor();
}
//设置最大连接数
initializeConnectionLatch();
//初始化Poller并开启线程监听事件队列
poller = new Poller();
Thread pollerThread = new Thread(poller, getName() + "-ClientPoller");
pollerThread.setPriority(threadPriority);
pollerThread.setDaemon(true);
pollerThread.start();
//启动Acceptor
startAcceptorThread();
}
}
11.启动Acceptor
开启Acceptor线程来监听socket
//AbstractEndpoint
protected void startAcceptorThread() {
acceptor = new Acceptor<>(this);
String threadName = getName() + "-Acceptor";
acceptor.setThreadName(threadName);
Thread t = new Thread(acceptor, threadName);
t.setPriority(getAcceptorThreadPriority());
t.setDaemon(getDaemon());
t.start();
}