spring boot war启动是利用Servlet 3.0新增的ServletContainerInitializer接口实现的。
主逻辑
-
Spring在spring-web-version.jar/META-INF/services/javax.servlet.ServletContainerInitializer文件中,配置了spring对ServletContainerInitializer接口的实现类org.springframework.web.SpringServletContainerInitializer。
-
Servlet Container启动阶段扫描jar包中META-INF/services/javax.servlet.ServletContainerInitializer文件, 获取ServletContainerInitializer实现类并实例化,解析ServletContainerInitializer上@HandlesTypes注解,查找出@HandlesTypes限定的类型集合,作为ServletContainerInitializer.onStartup 方法处理的第一个参数c。
-
Servlet Container依次调用每个ServletContainerInitializer实例的onStartup。war包启动的场景中会调用SpringServletContainerInitializer.onStartup方法,该方法循环调用c集合中每个 WebApplicationInitializer子类(即SpringBootServletInitializer)的onStartup方法。
-
SpringBootServletInitializer.onStartup方法调用SpringBootServletInitializer.createRootApplicationContext方法,createRootApplicationContext方法中构建SpringApplication并执行SpringApplication.run方法以启动整个spring项目。
源码
Spring的ServletContainerInitializer实现类
@HandlesTypes(WebApplicationInitializer.class) public class SpringServletContainerInitializer implements ServletContainerInitializer { ...... @Override public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) throws ServletException { List<WebApplicationInitializer> initializers = new LinkedList<>(); if (webAppInitializerClasses != null) { for (Class<?> waiClass : webAppInitializerClasses) { // Be defensive: Some servlet containers provide us with invalid classes, // no matter what @HandlesTypes says... if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) && WebApplicationInitializer.class.isAssignableFrom(waiClass)) { try { initializers.add((WebApplicationInitializer)ReflectionUtils.accessibleConstructor(waiClass).newInstance()); } catch (Throwable ex) { throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex); } } } } if (initializers.isEmpty()) { servletContext.log("No Spring WebApplicationInitializer types detected on classpath"); return; } servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath"); AnnotationAwareOrderComparator.sort(initializers); for (WebApplicationInitializer initializer : initializers) { initializer.onStartup(servletContext); } } }
WebApplicationInitializer.class接口的实现类
public abstract class SpringBootServletInitializer implements WebApplicationInitializer { ...... @Override public void onStartup(ServletContext servletContext) throws ServletException { // Logger initialization is deferred in case an ordered // LogServletContextInitializer is being used this.logger = LogFactory.getLog(getClass()); WebApplicationContext rootAppContext = createRootApplicationContext(servletContext); ......//略去部分代码 } protected WebApplicationContext createRootApplicationContext( ServletContext servletContext) { SpringApplicationBuilder builder = createSpringApplicationBuilder(); builder.main(getClass()); ApplicationContext parent = getExistingRootWebApplicationContext(servletContext); ......//略去部分代码 return run(application); } protected WebApplicationContext run(SpringApplication application) { return (WebApplicationContext) application.run(); } }
spring boot main application class
@SpringBootApplication public class Application extends SpringBootServletInitializer { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }