springboot使用外置servlet容器原理

使用外置servlet容器

1)、必須創建一個war項目;(利用idea創建好目錄結構)

2)、將嵌入式的Tomcat指定爲provided;

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-tomcat</artifactId>
   <scope>provided</scope>
</dependency>

3)、必須編寫一個SpringBootServletInitializer的子類,並調用configure方法

public class ServletInitializer extends SpringBootServletInitializer {

   @Override
   protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
       //傳入SpringBoot應用的主程序
      return application.sources(SpringBoot04WebJspApplication.class);
   }

}

4)、啓動服務器就可以使用;

原理

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<Class<?>>;爲這些WebApplicationInitializer類型的類創建實例;
4)、每一個WebApplicationInitializer都調用自己的onStartup;在這裏插入圖片描述
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應用

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章