SpringBoot 使用外部 Tomcat 容器运行

继承 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 机制,是直接启动的,可以参看这里的内嵌 Tomcat 启动类:https://www.cnblogs.com/jhxxb/p/13564329.html


https://spring.io/blog/2014/03/07/deploying-spring-boot-applications

https://blog.csdn.net/f641385712/article/details/87474907

原文地址:https://www.cnblogs.com/jhxxb/p/13596565.html