嵌入式Servlet容器比较

嵌入式Servlet容器,应用打包成可执行的jar

优点:
简单、便携
缺点:
默认不支持JSP、优化定制比较复杂(ServerPropertiesEmbeddedServletContainerCustomizer以及EmbeddedServletContainerFactory)。

外置的Servlet容器:外部安装Tomcat,应用打成war包,放到Tomcat的webapps目录下。

使用外置Servlet步骤说明

1、创建web项目。
2、将嵌入式的Tomcat指定为provided。

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-tomcat</artifactId>
  4. <scope>provided</scope>
  5. </dependency>

3、编写一个SpringBootServletInitializer的子类,并调用configure方法。

  1. public class ServletInitializer extends SpringBootServletInitializer {
  2. @Override
  3. protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
  4. //传入SpringBoot应用的主程序
  5. return application.sources(SpringBoot04WebJspApplication.class);
  6. }
  7. }

4、启动服务器就可以使用

原理说明

jar包:执行Spring Boot主类的main方法,启动IOC容器,创建嵌入式的Servlet容器。
war包:启动服务器,服务器启动Spring Boot应用(SpringBootServletInitializer),启动ioc容器。

规则

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将@HandlesTypesWebApplicationInitializer.class)标注的所有这个类型的类都传入到onStartup方法的Set<Class<?>>,为这些WebApplicationInitializer类型的类创建实例。

4、每一个WebApplicationInitializer都调用自己的onStartup
搜狗截图20180302221835.png

5、相当于我们的SpringBootServletInitializer的类会被创建对象,并执行onStartup方法。

6、SpringBootServletInitializer实例执行onStartup的时候会createRootApplicationContext,创建容器。

  1. protected WebApplicationContext createRootApplicationContext(ServletContext servletContext) {
  2. //1、创建SpringApplicationBuilder
  3. SpringApplicationBuilder builder = createSpringApplicationBuilder();
  4. StandardServletEnvironment environment = new StandardServletEnvironment();
  5. environment.initPropertySources(servletContext, null);
  6. builder.environment(environment);
  7. builder.main(getClass());
  8. ApplicationContext parent = getExistingRootWebApplicationContext(servletContext);
  9. if (parent != null) {
  10. this.logger.info("Root context already created (using as parent).");
  11. servletContext.setAttribute(
  12. WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, null);
  13. builder.initializers(new ParentContextApplicationContextInitializer(parent));
  14. }
  15. builder.initializers(
  16. new ServletContextApplicationContextInitializer(servletContext));
  17. builder.contextClass(AnnotationConfigEmbeddedWebApplicationContext.class);
  18. // 调用configure方法,子类重写了这个方法,将SpringBoot的主程序类传入了进来
  19. builder = configure(builder);
  20. //使用builder创建一个Spring应用
  21. SpringApplication application = builder.build();
  22. if (application.getSources().isEmpty() && AnnotationUtils
  23. .findAnnotation(getClass(), Configuration.class) != null) {
  24. application.getSources().add(getClass());
  25. }
  26. Assert.state(!application.getSources().isEmpty(),
  27. "No SpringApplication sources have been defined. Either override the "
  28. + "configure method or add an @Configuration annotation");
  29. // Ensure error pages are registered
  30. if (this.registerErrorPageFilter) {
  31. application.getSources().add(ErrorPageFilterConfiguration.class);
  32. }
  33. //启动Spring应用
  34. return run(application);
  35. }

7)、Spring的应用就启动并且创建IOC容器

  1. public ConfigurableApplicationContext run(String... args) {
  2. StopWatch stopWatch = new StopWatch();
  3. stopWatch.start();
  4. ConfigurableApplicationContext context = null;
  5. FailureAnalyzers analyzers = null;
  6. configureHeadlessProperty();
  7. SpringApplicationRunListeners listeners = getRunListeners(args);
  8. listeners.starting();
  9. try {
  10. ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
  11. ConfigurableEnvironment environment = prepareEnvironment(listeners,applicationArguments);
  12. Banner printedBanner = printBanner(environment);
  13. context = createApplicationContext();
  14. analyzers = new FailureAnalyzers(context);
  15. prepareContext(context, environment, listeners, applicationArguments,printedBanner);
  16. //刷新IOC容器
  17. refreshContext(context);
  18. afterRefresh(context, applicationArguments);
  19. listeners.finished(context, null);
  20. stopWatch.stop();
  21. if (this.logStartupInfo) {
  22. new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
  23. }
  24. return context;
  25. } catch (Throwable ex) {
  26. handleRunFailure(context, listeners, analyzers, ex);
  27. throw new IllegalStateException(ex);
  28. }
  29. }

8、启动Servlet容器,再启动Spring Boot应用