SpringBoot系列之外部Servlet容器启动原理

外部Servlet容器启动springboot应用原理

了解外部Servlet容器启动springboot的原理,需要先了解一个规则,这个规则可以参考servlet3.0规范的8.2.4章 Shared libraries / runtimes pluggability:

本文摘录几条主要规则:
1)、服务器启动(web应用启动)会创建当前web应用里面每一个jar包里面ServletContainerInitializer实例:
2)、ServletContainerInitializer的实现放在jar包的META-INF/services文件夹下,有一个名为
javax.servlet.ServletContainerInitializer的文件,内容就是ServletContainerInitializer的实现类的全类名
3)、还可以使用@HandlesTypes,在应用启动的时候加载我们感兴趣的类;

这些规则有助于理解接下来讨论的springboot流程:
1)、启动Tomcat
2)、org\springframework\spring-web\4.3.14.RELEASE\spring-web-4.3.14.RELEASE.jar!\METAINF\services\javax.servlet.ServletContainerInitializer:
Spring的web模块里面有这个文件:org.springframework.web.SpringServletContainerInitializer
3)、SpringServletContainerInitializer将@HandlesTypes(WebApplicationInitializer.class)标注的所有这个类型
的类都传入到onStartup方法的Set;为这些WebApplicationInitializer类型的类创建实例;

SpringBoot系列之外部Servlet容器启动原理_第1张图片

注:上一篇文章说的使用外部容器启动需要编写一个SpringBootServletInitializer的子类,通过继承树可以看到就是WebApplicationInitializer的子类
4)、每一个WebApplicationInitializer都调用自己的onStartup;
5)、相当于我们的SpringBootServletInitializer的类会被创建对象,并执行onStartup方法

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

protected WebApplicationContext createRootApplicationContext(
		ServletContext servletContext) {
	// 创建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应用

本文可简述如下:

1.创建SpringBootServletInitializer的子类并重写configure方法
2.configure方法中SpringApplicationBuilder传入SpringBootApplication主程序类
    – builder.source(@SpringBootApplication类)
3.启动原理
    – Servlet3.0标准ServletContainerInitializer扫描所有jar包中METAINF/services/javax.servlet.ServletContainerInitializer文件指定的类并加载
    – 加载spring web包下的SpringServletContainerInitializer
    – 扫描@HandleType(WebApplicationInitializer)
    – 加载SpringBootServletInitializer并运行onStartup方法
    – 加载@SpringBootApplication主类,启动容器等

你可能感兴趣的:(技术学习记录)