前面几篇内容主要几种在springboot启动时,我们接下去会探讨下请求到达spring容器的过程。
请求进入spring容器最先会进入tomcat,所以我们优先分析下tomcat
如图所示:tomcat的顶层容器是Server,一个tomcat顶多只有一个Server,一个Server下有多个Service,一个Service又包含多个Connectors和一个Container。Connectors用于处理连接欸相关的事情,并提供Socket与request转换,Container用于封装和管理Servlet以及处理具体的request请求。
Bootstrap是Tomcat的入口,正常情况下启动Tomcat就是调用Bootstrap的main方法
synchronized (daemonLock) {
if (daemon == null) {
// Don't set daemon until init() has completed
Bootstrap bootstrap = new Bootstrap();
try {
bootstrap.init();
} catch (Throwable t) {
handleThrowable(t);
t.printStackTrace();
return;
}
daemon = bootstrap;
。。。。。
bootstrap.init(); 这里会调用bootstrap的init方法
public void init() throws Exception {
initClassLoaders();
Thread.currentThread().setContextClassLoader(catalinaLoader);
SecurityClassLoad.securityClassLoad(catalinaLoader);
// Load our startup class and call its process() method
if (log.isDebugEnabled())
log.debug("Loading startup class");
Class<?> startupClass = catalinaLoader.loadClass("org.apache.catalina.startup.Catalina");
Object startupInstance = startupClass.getConstructor().newInstance();
// Set the shared extensions class loader
if (log.isDebugEnabled())
log.debug("Setting startup class properties");
String methodName = "setParentClassLoader";
Class<?> paramTypes[] = new Class[1];
paramTypes[0] = Class.forName("java.lang.ClassLoader");
Object paramValues[] = new Object[1];
paramValues[0] = sharedLoader;
Method method =
startupInstance.getClass().getMethod(methodName, paramTypes);
method.invoke(startupInstance, paramValues);
catalinaDaemon = startupInstance;
}
这段代码主要初始化了一个classLoader,然后把这个classloader设置在当前线程上(这是因为双亲委托这个模型,具体可以百度双亲委托模型)。随后用这个classLoader创建了Catalina实例,然后赋值给catalinaDaemon,后续的命令都用catalinaDaemon来执行。
我们回到bootstrap的main方法
try {
。。。。
} else if (command.equals("start")) {
daemon.setAwait(true);
daemon.load(args);
daemon.start();
。。。。
。。。。。
} else {
log.warn("Bootstrap: command \"" + command + "\" does not exist.");
}
这里通过 daemon.start();启动tomcat
public void start()
throws Exception {
if( catalinaDaemon==null ) init();
Method method = catalinaDaemon.getClass().getMethod("start", (Class [] )null);
method.invoke(catalinaDaemon, (Object [])null);
}
通过反射来调用catalinaDaemon的start方法
我们接下去主要分析catalinaDaemon的start方法
public void start() {
if (getServer() == null) {
load();
}
if (getServer() == null) {
log.fatal(sm.getString("catalina.noServer"));
return;
}
long t1 = System.nanoTime();
// Start the new server
try {
getServer().start();
} catch (LifecycleException e) {
log.fatal(sm.getString("catalina.serverStartFail"), e);
try {
getServer().destroy();
} catch (LifecycleException e1) {
log.debug("destroy() failed for failed Server ", e1);
}
return;
}
long t2 = System.nanoTime();
if(log.isInfoEnabled()) {
log.info(sm.getString("catalina.startup", Long.valueOf((t2 - t1) / 1000000)));
}
// Register shutdown hook
if (useShutdownHook) {
if (shutdownHook == null) {
shutdownHook = new CatalinaShutdownHook();
}
Runtime.getRuntime().addShutdownHook(shutdownHook);
// If JULI is being used, disable JULI's shutdown hook since
// shutdown hooks run in parallel and log messages may be lost
// if JULI's hook completes before the CatalinaShutdownHook()
LogManager logManager = LogManager.getLogManager();
if (logManager instanceof ClassLoaderLogManager) {
((ClassLoaderLogManager) logManager).setUseShutdownHook(
false);
}
}
if (await) {
await();
stop();
}
}
首先会调用 load();方法去加载server.xml中文件中的配置内容,初始化一个server。
随后会通过getServer().start()这句话来启动server容器
我们跟踪进入这个方法
Tomcat默认的Server实现类是StanardServer,StanardServer继承了LifecycleMBeanBase,而LifecycleMBeanBase又继承了
LifecycleBase,start方法就定义在LifecycleBase中,init方法也定义在上面
我们先看下Server这个接口
关注到有一个addService和removeService方法。我们之前说过一个server中会包含多个Service,addService就是在Server中添加Service的。
我们进入LifecycleBase的start方法
。。。。。
if (state.equals(LifecycleState.NEW)) {
init();
} else if (state.equals(LifecycleState.FAILED)){
stop();
。。。。
。。。。。。
startInternal();
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
setStateInternal(LifecycleState.FAILED, null, false);
throw new LifecycleException(
sm.getString("lifecycleBase.startFail",toString()), t);
}
if (state.equals(LifecycleState.FAILED) ||
state.equals(LifecycleState.MUST_STOP)) {
stop();
} else {
// Shouldn't be necessary but acts as a check that sub-classes are
// doing what they are supposed to.
if (!state.equals(LifecycleState.STARTING)) {
invalidTransition(Lifecycle.AFTER_START_EVENT);
}
setStateInternal(LifecycleState.STARTED, null, false);
}
}
省略前面一大串废话,我们看到init。点击进入
@Override
public final synchronized void init() throws LifecycleException {
。。。。
initInternal();
。。。。
再进入initInternal();方法
protected abstract void initInternal() throws LifecycleException;是一个模板方法,会由子类自己去实现,我们进入standardServer的initInternal方法
@Override
protected void initInternal() throws LifecycleException {
。。。。。。废话一大堆
// Initialize our defined Services
for (int i = 0; i < services.length; i++) {
services[i].init();
}
}
前面一大串都忽略掉,直接看最后一句话
for (int i = 0; i < services.length; i++) { services[i].init(); }会发现这里是循环调用每一个services的init方法
然后看到 startInternal();这也是一个模板方法,我们看到standardServer的实现
protected void startInternal() throws LifecycleException {
。。。。。。
synchronized (servicesLock) {
for (int i = 0; i < services.length; i++) {
services[i].start();
}
}
}
和前面的init一样,也是循环调用每一个service的start方法
我们回到catalina的start方法
注意到start方法的最后又一句话
if (await) {
await();
stop();
}
我们点击最终进入的是StandardServer的await方法
public void await() {
// Negative values - don't wait on port - tomcat is embedded or we just don't like ports
if( port == -2 ) {
// undocumented yet - for embedding apps that are around, alive.
return;
}
if( port==-1 ) {
try {
awaitThread = Thread.currentThread();
while(!stopAwait) {
try {
Thread.sleep( 10000 );
} catch( InterruptedException ex ) {
// continue and check the flag
}
}
} finally {
awaitThread = null;
}
return;
}
// Set up a server socket to wait on
try {
awaitSocket = new ServerSocket(port, 1,
InetAddress.getByName(address));
} catch (IOException e) {
log.error("StandardServer.await: create[" + address
+ ":" + port
+ "]: ", e);
return;
}
try {
awaitThread = Thread.currentThread();
// Loop waiting for a connection and a valid command
while (!stopAwait) {
ServerSocket serverSocket = awaitSocket;
if (serverSocket == null) {
break;
}
// Wait for the next connection
Socket socket = null;
StringBuilder command = new StringBuilder();
try {
InputStream stream;
try {
socket = serverSocket.accept();
socket.setSoTimeout(10 * 1000); // Ten seconds
stream = socket.getInputStream();
} catch (AccessControlException ace) {
log.warn("StandardServer.accept security exception: "
+ ace.getMessage(), ace);
continue;
} catch (IOException e) {
if (stopAwait) {
// Wait was aborted with socket.close()
break;
}
log.error("StandardServer.await: accept: ", e);
break;
}
// Read a set of characters from the socket
int expected = 1024; // Cut off to avoid DoS attack
while (expected < shutdown.length()) {
if (random == null)
random = new Random();
expected += (random.nextInt() % 1024);
}
while (expected > 0) {
int ch = -1;
try {
ch = stream.read();
} catch (IOException e) {
log.warn("StandardServer.await: read: ", e);
ch = -1;
}
if (ch < 32) // Control character or EOF terminates loop
break;
command.append((char) ch);
expected--;
}
} finally {
// Close the socket now that we are done with it
try {
if (socket != null) {
socket.close();
}
} catch (IOException e) {
// Ignore
}
}
// Match against our command string
boolean match = command.toString().equals(shutdown);
if (match) {
log.info(sm.getString("standardServer.shutdownViaPort"));
break;
} else
log.warn("StandardServer.await: Invalid command '"
+ command.toString() + "' received");
}
} finally {
ServerSocket serverSocket = awaitSocket;
awaitThread = null;
awaitSocket = null;
// Close the server socket and return
if (serverSocket != null) {
try {
serverSocket.close();
} catch (IOException e) {
// Ignore
}
}
}
}
一大串方法。归纳一下就做了一件事,让服务器进入端口监听状态
我们接下去分析下service的start方法
service也同样继承了LifecycleMBeanBase,而LifecycleMBeanBase又继承了LifecycleBase
所以start方法最终还是会去调用service默认实现类的initInternal和startInternal方法
tomcat默认实现的service是StandardService
@Override
protected void initInternal() throws LifecycleException {
super.initInternal();
if (container != null) {
container.init();
}
// Initialize any Executors
for (Executor executor : findExecutors()) {
if (executor instanceof JmxEnabled) {
((JmxEnabled) executor).setDomain(getDomain());
}
executor.init();
}
// Initialize mapper listener
mapperListener.init();
// Initialize our defined 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);
}
}
}
}
initInternal可以看到主要是调用container,excutors,mapperListener,connectors的init方法,因为connectors在一个service中有多个,所以会循环调用每一个connectors的init方法,container和connectors我们之前已经讲过了,mapperListener是Mapper的监听器,可以监听container容器的变化,executors是用在connectors中管理线程的线程池。
我们可以用这样一张时序图来演示tomcat的启动过程
-----------------------------------------------------------------------
上面我们刚刚分析完tomcat启动的整体流程,我们可以发现,server,service的start方法都是调用lifecycle的start方法,最终是调用默认实现类的initInternal和startInternal方法,其实我们下一篇会说到的container和connectors的start方法也是一样的。这里说明lifecycle是一个非常重要的接口,它控制着tomcat的生命周期
我们直接看lifecycle接口
首先这个接口定义了13个Stirng常量,用于各种事件的type属性中,(具体可以看lifecycleEvent接口,这里不细说)。然后定义了三个管理监听器的方法addLifecycleListener。。。。findLifecyleListener。。。removeLifecycleListner。。。。然后就是4个生命周期相关的方法,init,start,stop,destory,最后就是获取当前状态的两个方法,getState和getStateName,用来获取当前的状态
LifecycleBase是Lifecycle的默认实现,这里我们不细说三个管理监听器的方法。
生命周期的方法都调用了各自的模板方法,比如init调用了initInternal模板方法,start调用了startInternal方法。
我们找到start方法来分析一下
@Override public final synchronized void start() throws LifecycleException { if (LifecycleState.STARTING_PREP.equals(state) || LifecycleState.STARTING.equals(state) || LifecycleState.STARTED.equals(state)) { if (log.isDebugEnabled()) { Exception e = new LifecycleException(); log.debug(sm.getString("lifecycleBase.alreadyStarted", toString()), e); } else if (log.isInfoEnabled()) { log.info(sm.getString("lifecycleBase.alreadyStarted", toString())); } return; } if (state.equals(LifecycleState.NEW)) { init(); } else if (state.equals(LifecycleState.FAILED)){ stop(); } else if (!state.equals(LifecycleState.INITIALIZED) && !state.equals(LifecycleState.STOPPED)) { invalidTransition(Lifecycle.BEFORE_START_EVENT); } setStateInternal(LifecycleState.STARTING_PREP, null, false); try { startInternal(); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); setStateInternal(LifecycleState.FAILED, null, false); throw new LifecycleException( sm.getString("lifecycleBase.startFail",toString()), t); } if (state.equals(LifecycleState.FAILED) || state.equals(LifecycleState.MUST_STOP)) { stop(); } else { // Shouldn't be necessary but acts as a check that sub-classes are // doing what they are supposed to. if (!state.equals(LifecycleState.STARTING)) { invalidTransition(Lifecycle.AFTER_START_EVENT); } setStateInternal(LifecycleState.STARTED, null, false); }
其实四个方法的形式都是类似的,都是先判断下状态,如果符合就调用相应的模板方法,不符合就抛异常。。
先分析到这里,下一篇将分析下Container和Connectors