繼承 SpringBootServletInitializer 類,重寫 configure 方法
@SpringBootApplication public class SpisApplication extends SpringBootServletInitializer { public static void main(String[] args) { SpringApplication.run(SpisApplication.class, args); } @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) { return builder.sources(SpisApplication.class); } }
原理
servlet 部分
從 servlet 3.0 開始,Tomcat 啟動時會自動加載實現了 ServletContainerInitializer 接口的類(需要在 META-INF/services 目錄下新建配置文件)。也稱為 SPI 機制
package javax.servlet; import java.util.Set; public interface ServletContainerInitializer { public void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException; }
spring 部分
SpringServletContainerInitializer 的 onStartup 會被執行,webAppInitializerClasses 參數是所有實現了 WebApplicationInitializer 接口的類(servlet 注解 @HandlesTypes(WebApplicationInitializer.class) 的作用)
package org.springframework.web; import java.lang.reflect.Modifier; import java.util.LinkedList; import java.util.List; import java.util.ServiceLoader; import java.util.Set; import javax.servlet.ServletContainerInitializer; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.annotation.HandlesTypes; import org.springframework.core.annotation.AnnotationAwareOrderComparator; import org.springframework.lang.Nullable; import org.springframework.util.ReflectionUtils; @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) { 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); } } }
再看 SpringBoot 啟動類所需要繼承的類
public abstract class SpringBootServletInitializer implements WebApplicationInitializer
就是這個接口,所以 Tomcat 啟動時 SpringBoot 也就跟着啟動了
public interface WebApplicationInitializer { void onStartup(ServletContext servletContext) throws ServletException; }
附上利用 Servlet 該特性的 SSM 整合:https://www.cnblogs.com/jhxxb/p/10512553.html
SpringBoot 內嵌 Tomcat 的啟動不是 SPI 機制,是直接啟動的。
https://spring.io/blog/2014/03/07/deploying-spring-boot-applications