嵌入式Servlet容器比较
嵌入式Servlet容器,应用打包成可执行的jar
优点:
简单、便携
缺点:
默认不支持JSP、优化定制比较复杂(ServerProperties、EmbeddedServletContainerCustomizer以及EmbeddedServletContainerFactory)。
外置的Servlet容器:外部安装Tomcat,应用打成war包,放到Tomcat的webapps目录下。
使用外置Servlet步骤说明
1、创建web项目。
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 {@Overrideprotected SpringApplicationBuilder configure(SpringApplicationBuilder application) {//传入SpringBoot应用的主程序return application.sources(SpringBoot04WebJspApplication.class);}}
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将@HandlesTypes(WebApplicationInitializer.class)标注的所有这个类型的类都传入到onStartup方法的Set<Class<?>>,为这些WebApplicationInitializer类型的类创建实例。
4、每一个WebApplicationInitializer都调用自己的onStartup。
5、相当于我们的SpringBootServletInitializer的类会被创建对象,并执行onStartup方法。
6、SpringBootServletInitializer实例执行onStartup的时候会createRootApplicationContext,创建容器。
protected WebApplicationContext createRootApplicationContext(ServletContext servletContext) {//1、创建SpringApplicationBuilderSpringApplicationBuilder 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 registeredif (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);}}
8、启动Servlet容器,再启动Spring Boot应用
