1 前言
1.1 内嵌servlet 容器的情况下
根据SpringBoot的启动原理,可以知道,是通过以下代码可以直接,启动SpringBoot应用(就是SpringApplication.run(...)
方法):
@SpringBootApplication
public class SpringBootApplicationStarter {
public static void main(String[] args) {
SpringApplication.run(SpringBootApplicationStarter.class, args);
}
}
1.2 在外置servlet容器的情况下
同上,同样是调用了SpringApplication.run(...)
方法,不过需要先启动 服务器,再间接创建->初始化->启动SpringBoot应用,以下就是这种情况下的SpringBoot启动流程:
这种启动流程原理,是依赖Servlet3.1规范的(大致如下):
-
根据Servlet3.1规范,服务器启动(web应用启动)会创建当前web应用里面每一个jar包里面
ServletContainerInitializer
的实例。 -
ServletContainerInitializer
的实现放在jar包的META-INF/services
文件夹下,有一个名为javax.servlet.ServletContainerInitializer
的文件,内容就是ServletContainerInitializer
的实现类的全类名。 -
在任何
Servlet Listener
的事件被触发之前,当应用正在启动时,ServletContainerInitializer
的onStartup
方法将被调用。 -
ServletContainerInitializer
实现上的@handlesTypes
注解用于寻找感兴趣的类,要么是@HandlesTypes
注解指定的类,要么是指定类的子类。
1.2.1 启动流程(以Tomcat为例)
-
Tomcat启动
-
根据Servlet3.1规范,找到 ServletContainerInitializer 的实现,进行实例化
-
创建 ServletContainerInitializer 实例
-
调用 ServletContainerInitializer 实例 (
SpringServletContainerInitializer
)的 onStartup 方法 -
SpringBoot 应用,就是在 onStartup 方法中启动的
1.2.2 ServletContainerInitializer 接口
ServletContainerInitializer
就是一个接口,只有一个待实现的方法onStartup
// javax/servlet/ServletContainerInitializer.class
public interface ServletContainerInitializer {
void onStartup(Set<Class<?>> var1, ServletContext var2) throws ServletException;
}
2 外置Tomcat启动SpringBoot的流程原理
2.1 Tomcat 启动
重点看下 StandardContext
类的 startInternal
方法
protected synchronized void startInternal() throws LifecycleException {
// 略
// 调用 所有的 ServletContainerInitializer 的 onStartup 方法
for (Map.Entry<ServletContainerInitializer, Set<Class<?>>> entry :
initializers.entrySet()) {
try {
entry.getKey().onStartup(entry.getValue(),
getServletContext());
} catch (ServletException e) {
log.error(sm.getString("standardContext.sciFail"), e);
ok = false;
break;
}