天津储鑫盛钢材现货供应商 发表于 2024-5-13 06:26:22

SpringBoot使用外部Web容器的解决方案

Spring Boot 默认内嵌了Web容器(如Tomcat、Jetty或Undertow),这使得应用可以作为独立的可执行JAR或WAR文件运行,无需外部Web容器。然而,在某些环境下,你可能想要将Spring Boot应用摆设到外部的Web容器中,好比Apache Tomcat或Jetty。
嵌入式的Web容器:应用可以打包成可执行的Jar。
优点:简朴、便携。
缺点:默认不支持JSP、优化定制比较复杂(使用定制器ServerProperties、自界说EmbeddedServletContainerCustomizer,本身编写嵌入式Servlet容器的创建工厂EmbeddedServletContainerFactory)。
外部的Web容器:外面安装Tomcat服务器,应用war包的方式打包运行。
解决步调

将Spring Boot应用摆设到外部的Web容器的步调:
1.创建一个Maven项目,声明为WAR。
2.排除内嵌Tomcat容器
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
      <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
      </exclusion>
    </exclusions>
</dependency>3.重新导入Tomcat启动器,依赖范围改为provided
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-tomcat</artifactId>
   <scope>provided</scope>
</dependency>4.必须编写一个SpringBootServletInitializer的子类,并调用configure方法
public class ServletInitializer extends SpringBootServletInitializer {

   @Override
   protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
       //传入SpringBoot应用的主程序
      return application.sources(SpringBootWebApplication.class);
   }
}5.启动服务器就可以使用。
底层原理

JAR包:执行SpringBoot主类的main方法,启动ioc容器,创建嵌入式的Servlet容器。
WAR包:启动Tomcat服务器,服务器启动SpringBoot应用SpringBootServletInitializer,然后启动ioc容器。
检察Servlet3.0及以上的运行规则
1)服务器启动(web应用启动)会创建当前web应用里面每一个jar包里面ServletContainerInitializer实例。
2)ServletContainerInitializer的实现放在jar包的META-INF/services文件夹下,有一个名为javax.servlet.ServletContainerInitializer的文件,内容就是ServletContainerInitializer的实现类的全类名。
3)还可以使用@HandlesTypes,在应用启动的时候加载我们感兴趣的类。
流程
1.启动Tomcat
2.检察文件内容
org\springframework\spring-web\4.3.14.RELEASE\spring-web-4.3.14.RELEASE.jar!\META-INF\services\javax.servlet.ServletContainerInitializer:
Spring的web模块里面有这个文件:org.springframework.web.SpringServletContainerInitializer
3.SpringServletContainerInitializer将@HandlesTypes(WebApplicationInitializer.class)标注的全部这个类型的类都传入到onStartup方法的泛型参数Set中;为这些WebApplicationInitializer类型的类创建实例
4.每一个WebApplicationInitializer都调用本身的onStartup
https://img2024.cnblogs.com/blog/3382744/202403/3382744-20240307112645406-745001347.png
5.相当于我们的SpringBootServletInitializer的类会被创建对象,并执行onStartup方法
6.SpringBootServletInitializer实例执行onStartup的时候会createRootApplicationContext,创建容器。源码检察:
protected WebApplicationContext createRootApplicationContext(
      ServletContext servletContext) {
    //1、创建SpringApplicationBuilder
   SpringApplicationBuilder builder = createSpringApplicationBuilder();
   StandardServletEnvironment environment = new StandardServletEnvironment();
   environment.initPropertySources(servletContext, null);
   builder.environment(environment);
   builder.main(getClass());
   ApplicationContext parent = getExistingRootWebApplicationContext(servletContext);
   if (parent != null) {
      this.logger.info("Root context already created (using as parent).");
      servletContext.setAttribute(
            WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, null);
      builder.initializers(new ParentContextApplicationContextInitializer(parent));
   }
   builder.initializers(
         new ServletContextApplicationContextInitializer(servletContext));
   builder.contextClass(AnnotationConfigEmbeddedWebApplicationContext.class);
   
    //调用configure方法,子类重写了这个方法,将SpringBoot的主程序类传入了进来
   builder = configure(builder);
   
    //使用builder创建一个Spring应用
   SpringApplication application = builder.build();
   if (application.getSources().isEmpty() && AnnotationUtils
         .findAnnotation(getClass(), Configuration.class) != null) {
      application.getSources().add(getClass());
   }
   Assert.state(!application.getSources().isEmpty(),
         "No SpringApplication sources have been defined. Either override the "
               + "configure method or add an @Configuration annotation");
   // Ensure error pages are registered
   if (this.registerErrorPageFilter) {
      application.getSources().add(ErrorPageFilterConfiguration.class);
   }
    //启动Spring应用
   return run(application);
}7.Spring的应用就启动并且创建IOC容器
public ConfigurableApplicationContext run(String... args) {
   StopWatch stopWatch = new StopWatch();
   stopWatch.start();
   ConfigurableApplicationContext context = null;
   FailureAnalyzers analyzers = null;
   configureHeadlessProperty();
   SpringApplicationRunListeners listeners = getRunListeners(args);
   listeners.starting();
   try {
      ApplicationArguments applicationArguments = new DefaultApplicationArguments(
            args);
      ConfigurableEnvironment environment = prepareEnvironment(listeners,
            applicationArguments);
      Banner printedBanner = printBanner(environment);
      context = createApplicationContext();
      analyzers = new FailureAnalyzers(context);
      prepareContext(context, environment, listeners, applicationArguments,
            printedBanner);
      
       //刷新IOC容器
      refreshContext(context);
      afterRefresh(context, applicationArguments);
      listeners.finished(context, null);
      stopWatch.stop();
      if (this.logStartupInfo) {
         new StartupInfoLogger(this.mainApplicationClass)
               .logStarted(getApplicationLog(), stopWatch);
      }
      return context;
   }
   catch (Throwable ex) {
      handleRunFailure(context, listeners, analyzers, ex);
      throw new IllegalStateException(ex);
   }
}结论:启动Servlet容器,再启动SpringBoot应用

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: SpringBoot使用外部Web容器的解决方案