Tomcat Init过程分析
开篇
这篇文章主要是把Tomcat的初始化过程的时序图和源码进行结合,加深一下印象,同时在分析源码过程中会分析下Tomcat的代码设计结构供自己提升抽象能力。
Tomcat启动过程时序图
Tomcat 启动过程流程图说明:
- Tomcat的整个服务器启动包括初始化过程和启动过程
- 该篇文章主要是分析init()初始化过程
Tomcat启动过程 - Bootstrap
-
Bootstrap作为Tomcat的启动入口,直接关注main()函数入口。
-
Bootstrap通过 bootstrap.init()初始化自身对象。
-
通过调用daemon.load()方法执行Bootstrap的load()方法。
-
Bootstrap的load()方法的方法内部调用Catalina的load()方法。
public final class Bootstrap {
public static void main(String args[]) {
if (daemon == null) {
Bootstrap bootstrap = new Bootstrap();
try {
// 初始化Bootstrap对象
bootstrap.init();
} catch (Throwable t) {
handleThrowable(t);
t.printStackTrace();
return;
}
daemon = bootstrap;
} else {
Thread.currentThread().setContextClassLoader(daemon.catalinaLoader);
}
try {
String command = "start";
if (args.length > 0) {
command = args[args.length - 1];
}
if (command.equals("startd")) {
args[args.length - 1] = "start";
// Catalina初始化过程入口
daemon.load(args);
daemon.start();
} else if (command.equals("stopd")) {
args[args.length - 1] = "stop";
daemon.stop();
} else if (command.equals("start")) {
daemon.setAwait(true);
// 初始化流程步骤,负责调用Bootstrap.load()接口
daemon.load(args);
daemon.start();
if (null == daemon.getServer()) {
System.exit(1);
}
} else if (command.equals("stop")) {
daemon.stopServer(args);
} else if (command.equals("configtest")) {
daemon.load(args);
if (null == daemon.getServer()) {
System.exit(1);
}
System.exit(0);
} else {
log.warn("Bootstrap: command \"" + command + "\" does not exist.");
}
} catch (Throwable t) {
// 省略相关代码
}
}
private void load(String[] arguments)
throws Exception {
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;
}
Method method =
catalinaDaemon.getClass().getMethod(methodName, paramTypes);
if (log.isDebugEnabled())
log.debug("Calling startup class " + method);
method.invoke(catalinaDaemon, param);
}
}
Tomcat启动过程 - Catalina
-
Catalina的方法内部省略了一些初始化自身的代码。
-
通过调用getServer().init()初始化了Server对象。
public class Catalina {
public void load() {
// 省略解析xml生成对象的逻辑
getServer().setCatalina(this);
getServer().setCatalinaHome(Bootstrap.getCatalinaHomeFile());
getServer().setCatalinaBase(Bootstrap.getCatalinaBaseFile());
initStreams();
// 初始化Server对象
try {
getServer().init();
} catch (LifecycleException e) {
if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE")) {
throw new java.lang.Error(e);
} else {
log.error("Catalina.start", e);
}
}
long t2 = System.nanoTime();
if(log.isInfoEnabled()) {
log.info("Initialization processed in " + ((t2 - t1) / 1000000) + " ms");
}
}
}
Tomcat启动过程 - Lifecycle
Tomcat的Lifecycle的设计非常具体抽象性和层次性,每个层次只做通用的事情,具体的事情交由子类进行实现。
-
Tomcat的实现过程中有一个生命周期控制的Interface的定义Lifecycle,容器都基于该interface进行实现。
-
Lifecycle接口主要定义了init & start & stop & destroy 等通用方法,由各具体类具体实现,但是接口调用方法可以统一进行调用。
-
LifecycleBase实现了Lifecycle接口,实现init()接口的通用流程并抽象出initInternal()方法供子类进行具体实现。
-
LifecycleMBeanBase继承了LifecycleBase,实现initInternal()方法,子类如果不覆盖该父类方法,那么就成为通用的方法了。
public interface Lifecycle {
public static final String BEFORE_INIT_EVENT = "before_init";
public static final String AFTER_INIT_EVENT = "after_init";
public static final String START_EVENT = "start";
public static final String BEFORE_START_EVENT = "before_start";
public static final String AFTER_START_EVENT = "after_start";
public static final String STOP_EVENT = "stop";
public static final String BEFORE_STOP_EVENT = "before_stop";
public static final String AFTER_STOP_EVENT = "after_stop";
public static final String AFTER_DESTROY_EVENT = "after_destroy";
public static final String BEFORE_DESTROY_EVENT = "before_destroy";
public static final String PERIODIC_EVENT = "periodic";
public static final String CONFIGURE_START_EVENT = "configure_start";
public static final String CONFIGURE_STOP_EVENT = "configure_stop";
public void addLifecycleListener(LifecycleListener listener);
public LifecycleListener[] findLifecycleListeners();
public void removeLifecycleListener(LifecycleListener listener);
public void init() throws LifecycleException;
public void start() throws LifecycleException;
public void stop() throws LifecycleException;
public void destroy() throws LifecycleException;
public LifecycleState getState();
public String getStateName();
public interface SingleUse {
}
}
public abstract class LifecycleBase implements Lifecycle {
public final synchronized void init() throws LifecycleException {
if (!state.equals(LifecycleState.NEW)) {
invalidTransition(Lifecycle.BEFORE_INIT_EVENT);
}
try {
setStateInternal(LifecycleState.INITIALIZING, null, false);
initInternal();
setStateInternal(LifecycleState.INITIALIZED, null, false);
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
setStateInternal(LifecycleState.FAILED, null, false);
throw new LifecycleException(
sm.getString("lifecycleBase.initFail",toString()), t);
}
}
protected abstract void initInternal() throws LifecycleException;
}
public abstract class LifecycleMBeanBase extends LifecycleBase
implements JmxEnabled {
private static final Log log = LogFactory.getLog(LifecycleMBeanBase.class);
private static final StringManager sm =
StringManager.getManager("org.apache.catalina.util");
/* Cache components of the MBean registration. */
private String domain = null;
private ObjectName oname = null;
protected MBeanServer mserver = null;
@Override
protected void initInternal() throws LifecycleException {
if (oname == null) {
mserver = Registry.getRegistry(null, null).getMBeanServer();
oname = register(this, getObjectNameKeyProperties());
}
}
}
Tomcat启动过程 - Server初始化
-
Server的初始化过程省略了一部分自身对象属性的初始化过程,调用super.initInternal()方法完成通用的属性初始化。
-
Server内部负责实现Service的初始化,通过services[i].init()实现。
public final class StandardServer extends LifecycleMBeanBase implements Server {
@Override
protected void initInternal() throws LifecycleException {
super.initInternal();
// 省略相关核心代码
// 负责启动 Services
for (int i = 0; i < services.length; i++) {
services[i].init();
}
}
}
Tomcat启动过程 - Service初始化
-
Service初始化过程中执行Engine.init()初始化Engine对象。
-
Service初始化过程中执行Executor.init()初始化Executor对象。
-
Service初始化过程中执行mapperListener.init()初始化mapperListener对象。
-
Service初始化过程中执行connector.init()初始化Connector对象。
public class StandardService extends LifecycleMBeanBase implements Service {
protected void initInternal() throws LifecycleException {
super.initInternal();
// 初始化Engine对象
if (engine != null) {
engine.init();
}
// 初始化Executor对象
for (Executor executor : findExecutors()) {
if (executor instanceof JmxEnabled) {
((JmxEnabled) executor).setDomain(getDomain());
}
executor.init();
}
// 初始化 mapper listener
mapperListener.init();
// 初始化 Connectors
synchronized (connectorsLock) {
for (Connector connector : connectors) {
try {
connector.init();
} catch (Exception e) {
String message = sm.getString(
"standardService.connector.initFailed", connector);
log.error(message, e);
if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE"))
throw new LifecycleException(message);
}
}
}
}
}
Tomcat启动过程 - ContainerBase
-
ContainerBase继承LifecycleMBeanBase类,覆写initInternal()方法。
-
ContainerBase的initInternal()方法内部初始化了startStopExecutor对象。
public abstract class ContainerBase extends LifecycleMBeanBase
implements Container {
protected void initInternal() throws LifecycleException {
BlockingQueue<Runnable> startStopQueue = new LinkedBlockingQueue<>();
startStopExecutor = new ThreadPoolExecutor(
getStartStopThreadsInternal(),
getStartStopThreadsInternal(), 10, TimeUnit.SECONDS,
startStopQueue,
new StartStopThreadFactory(getName() + "-startStop-"));
startStopExecutor.allowCoreThreadTimeOut(true);
super.initInternal();
}
}
Tomcat启动过程 - Engine初始化
- Engine初始化的过程中只初始化了Engine对象本身。
-
Engine初始化的过程中通过super.initInternal()调用ContainerBase的initInternal()方法。
public class StandardEngine extends ContainerBase implements Engine {
protected void initInternal() throws LifecycleException {
getRealm();
super.initInternal();
}
}
Tomcat启动过程 - Executor初始化
-
Executor初始化的过程中只初始化了Executor对象本身。
public class StandardThreadExecutor extends LifecycleMBeanBase
implements Executor, ResizableExecutor {
protected void initInternal() throws LifecycleException {
super.initInternal();
}
}
Tomcat启动过程 - Host初始化
- StandardHost的初始化是在start()过程中,而非在init过程中,所以暂时忽略。
-
StandardContext和StandardWrapper也在后面在叙述。
Tomcat启动过程 - Connector
- Connector初始化过程中初始化Connector对象。
- Connector初始化过程中初始化CoyoteAdapter对象。
- Connector初始化过程中初始化protocolHandler对象。
public class Connector extends LifecycleMBeanBase {
protected void initInternal() throws LifecycleException {
super.initInternal();
// Initialize adapter
adapter = new CoyoteAdapter(this);
protocolHandler.setAdapter(adapter);
// 省略相关代码
try {
// protocolHandler初始化
protocolHandler.init();
} catch (Exception e) {
throw new LifecycleException(
sm.getString("coyoteConnector.protocolHandlerInitializationFailed"), e);
}
}
}
Tomcat启动过程 - ProtocolHandler
- ProtocolHandler的初始化过程中初始化endpoint对象。
- endpoint对象的初始化过程中会进入AbstractEndpoint的初始化过程。
public abstract class AbstractProtocol<S> implements ProtocolHandler,
MBeanRegistration {
public void init() throws Exception {
if (getLog().isInfoEnabled()) {
getLog().info(sm.getString("abstractProtocolHandler.init", getName()));
}
if (oname == null) {
// Component not pre-registered so register it
oname = createObjectName();
if (oname != null) {
Registry.getRegistry(null, null).registerComponent(this, oname, null);
}
}
if (this.domain != null) {
rgOname = new ObjectName(domain + ":type=GlobalRequestProcessor,name=" + getName());
Registry.getRegistry(null, null).registerComponent(
getHandler().getGlobal(), rgOname, null);
}
String endpointName = getName();
endpoint.setName(endpointName.substring(1, endpointName.length()-1));
endpoint.setDomain(domain);
endpoint.init();
}
}
Tomcat启动过程 - AbstractEndpoint
- AbstractEndpoint初始化过程中主要bind()执行绑定过程。
- AbstractEndpoint的bind()过程中初始化ServerSocker对象。
public abstract class AbstractEndpoint<S> {
public void init() throws Exception {
if (bindOnInit) {
bind();
bindState = BindState.BOUND_ON_INIT;
}
if (this.domain != null) {
// Register endpoint (as ThreadPool - historical name)
oname = new ObjectName(domain + ":type=ThreadPool,name=\"" + getName() + "\"");
Registry.getRegistry(null, null).registerComponent(this, oname, null);
for (SSLHostConfig sslHostConfig : findSslHostConfigs()) {
registerJmx(sslHostConfig);
}
}
}
}
public class NioEndpoint extends AbstractJsseEndpoint<NioChannel> {
public void bind() throws Exception {
if (!getUseInheritedChannel()) {
serverSock = ServerSocketChannel.open();
socketProperties.setProperties(serverSock.socket());
InetSocketAddress addr = (getAddress()!=null?new InetSocketAddress(getAddress(),getPort()):new InetSocketAddress(getPort()));
serverSock.socket().bind(addr,getAcceptCount());
} else {
// Retrieve the channel provided by the OS
Channel ic = System.inheritedChannel();
if (ic instanceof ServerSocketChannel) {
serverSock = (ServerSocketChannel) ic;
}
if (serverSock == null) {
throw new IllegalArgumentException(sm.getString("endpoint.init.bind.inherited"));
}
}
serverSock.configureBlocking(true); //mimic APR behavior
// Initialize thread count defaults for acceptor, poller
if (acceptorThreadCount == 0) {
// FIXME: Doesn't seem to work that well with multiple accept threads
acceptorThreadCount = 1;
}
if (pollerThreadCount <= 0) {
//minimum one poller thread
pollerThreadCount = 1;
}
setStopLatch(new CountDownLatch(pollerThreadCount));
// Initialize SSL if needed
initialiseSsl();
selectorPool.open();
}
}