前语
Tomcat源码版本为官网下载的9.0.35版本。
配置文件
Tomcat启动的配置文件为server.xml
,启动过程也全都围绕它进行,Tomcat的模块结构也可以在其中一览无余
<?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模块结构
Tomcat最重要的模块是Container容器,它层层包裹,像“套娃”一样一层套一层,便于管理内层的生命周期。其结构于配置文件server.xml
中的XML标签可以看得出来。首先记下理解这张图的模块结构,对下面源码启动的顺序理解帮助十分大。
生命周期
Tomcat中每个容器的生命周期都实现了一个接口Lifecycle
,其重要的方法有init
、start
、stop
、destroy
、getState
等。从它的继承树(仅展示部分)可以观察到,容器都实现了它:
启动类
其启动类为Bootstrap
,启动方法为main
方法。
public static void main(String args[]) { synchronized (daemonLock) { if (daemon == null) { // Don't set daemon until init() has completed Bootstrap bootstrap = new Bootstrap(); try { bootstrap.init(); } catch (Throwable t) { } daemon = bootstrap; } else { Thread.currentThread().setContextClassLoader(daemon.catalinaLoader); } } try { String command = "start"; // ... } else if (command.equals("start")) { daemon.setAwait(true); // 最重要的两步 -- daemon为Bootstrap类本身 // 第一步加载 -- 加载完会绑定监听socket端口(Tomcat 8开始使用NIO) daemon.load(args); // 第二步启动 -- 启动完才会去accept()处理请求 daemon.start(); if (null == daemon.getServer()) { System.exit(1); } } } catch (Throwable t) { } }
加载-load
加载过程,通过反射调用了Catalina
类的load
方法
/** * Load daemon. */ private void load(String[] arguments) throws Exception { // Call the load() method String methodName = "load"; Object param[]; Class<?> paramTypes[]; if (arguments==null || arguments.length==0) { paramTypes = null; param = null; } else { paramTypes = new Class[1]; paramTypes[0] = arguments.getClass(); param = new Object[1]; param[0] = arguments; } // 通过反射调用了`Catalina`类的`load`方法 Method method = catalinaDaemon.getClass().getMethod(methodName, paramTypes); if (log.isDebugEnabled()) { log.debug("Calling startup class " + method); } method.invoke(catalinaDaemon, param); }
其加载步骤按顺序有以下几步:
1. 读取配置文件
读取%home%/conf/server.xml配置文件,并用Digester
进行解析,将配置文件的容器等配置按照层次递归的放入Server
中,实际为StandardServer
这个类中。
// Set configuration source ConfigFileLoader.setSource(new CatalinaBaseConfigurationSource(Bootstrap.getCatalinaBaseFile(), getConfigFile())); File file = configFile(); // Create and execute our Digester Digester digester = createStartDigester(); // ... digester.push(this); digester.parse(inputSource);
2. 对server
对象进行初始化
getServer().init();
- 2.1 发现其初始化都是用超类
LifecycleBase
的final方法进行初始化的(Engine
、Host
、Context
、Wrapper
等都间接继承于它)。
public abstract class LifecycleBase implements Lifecycle { @Override public final synchronized void init() throws LifecycleException { // ... try { // 设置状态 setStateInternal(LifecycleState.INITIALIZING, null, false); // 真正执行初始化的方法 initInternal(); setStateInternal(LifecycleState.INITIALIZED, null, false); } catch (Throwable t) { handleSubClassException(t, "lifecycleBase.initFail", toString()); } } }
查看initInternal
方法的定义,发现他将这个方法交由子类进行具体实现,这里就提现了Java多态的模板方法的好处,继续看下去会发现,所有Containner
组件的初始化都经过init()
方法,最终由自己实现initInternal
方法,管理自己内部容器的初始化操作。
// LifecycleBase.java protected abstract void initInternal() throws LifecycleException;
继续进入initInternal
方法执行,进入了Server
的实现类StandardServer
中
// StandardServer.java @Override protected void initInternal() throws LifecycleException { super.initInternal(); // Initialize utility executor reconfigureUtilityExecutor(getUtilityThreadsInternal(utilityThreads)); // Initialize our defined Services // Server管理自己的套娃Service,最终也借用超类的init()方法对Service进行初始化 for (Service service : services) { // 对service进行init service.init(); } }
3. 对service
进行初始化
在第二步的末尾的循环中又进入了2.1
中的init
方法,再调用service
实现类StandardService
的initInternal
方法
// StandardService.java @Override protected void initInternal() throws LifecycleException { // 初始化Engine if (engine != null) { engine.init(); } // 初始化执行器 for (Executor executor : findExecutors()) { if (executor instanceof JmxEnabled) { ((JmxEnabled) executor).setDomain(getDomain()); } executor.init(); } // 初始化监听器 mapperListener.init(); // 初始化 Connectors (可以有多个连接器) synchronized (connectorsLock) { for (Connector connector : connectors) { connector.init(); } } }
4. 初始化引擎、执行器、监听器、连接器
- 初始化引擎
重要的仍是其实现父类的initInternal
方法,对Realm
(领域)的配置,实际获取了LockOutRealm
。
// StandardEngine.java @Override protected void initInternal() throws LifecycleException { getRealm(); // 这一步中还会有`ContainerBase`中创建`startStopExecuter`线程池供`start`启动阶段使用。 super.initInternal(); } // ContainerBase.java private void reconfigureStartStopExecutor(int threads) { if (threads == 1) { // Use a fake executor -- 虚假的线程池 if (!(startStopExecutor instanceof InlineExecutorService)) { startStopExecutor = new InlineExecutorService(); } } else { // Delegate utility execution to the Service Server server = Container.getService(this).getServer(); server.setUtilityThreads(threads); startStopExecutor = server.getUtilityExecutor(); } }
- 初始化执行器
源码中带的server.xml
中没有定义他,debug直接跳过了。 - 初始化监听器
// LifecycleMBeanBase.java // MapperListener.java 中并无实现initInternal方法,则一直调用到超类的额该方法 @Override protected void initInternal() throws LifecycleException { if (oname == null) { mserver = Registry.getRegistry(null, null).getMBeanServer(); // 将oname 赋值为Catalina:type=Mapper oname = register(this, getObjectNameKeyProperties()); } }
- 初始化连接器
@Override protected void initInternal() throws LifecycleException { // Initialize adapter adapter = new CoyoteAdapter(this); protocolHandler.setAdapter(adapter); if (service != null) { protocolHandler.setUtilityExecutor(service.getServer().getUtilityExecutor()); } try { // 对协议处理器进行初始化 protocolHandler.init(); } catch (Exception e) { throw new LifecycleException( sm.getString("coyoteConnector.protocolHandlerInitializationFailed"), e); } }