Spring源码-Springboot不使用默认的tomcat,使用外部tomcat原理


基于版本2.0.5.RELEASE

前言

ServletContainerInitializer(传递ServletContext)—>WebApplicationInitializer(创建SpringApplication)—>ApplicationContextInitializer(为spring上下文设置ServletContext属性)—>ServletContextInitializer(ServletContext设置DispatcherServlet)

一、tomcat启动过程

在web容器启动时为提供给第三方组件机会做一些初始化的工作,例如注册servlet或者filtes等,servlet规范中通过ServletContainerInitializer实现此功能。每个框架要使用ServletContainerInitializer就必须在对应的jar包的META-INF/services 目录创建一个名为javax.servlet.ServletContainerInitializer的文件,文件内容指定具体的ServletContainerInitializer实现类,那么,当web容器启动时就会运行这个初始化器做一些组件内的初始化工作。 spring-web模块下就有一个javax.servlet.ServletContainerInitializer文件,文件里内容为 **org.springframework.web.SpringServletContainerInitializer**

引用自https://blog.csdn.net/lolichan/article/details/84920534

二、SpringServletContainerInitializer类

类上方的HandlersType注解内容类会被tomcat扫描到实现类并作为参数放入onStartup方法,最终调用WebApplicationInitializer实现类的onStartup方法

@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {
@Override
	public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
			throws ServletException {

		List<WebApplicationInitializer> initializers = new LinkedList<>();

		if (webAppInitializerClasses != null) {
			for (Class<?> waiClass : webAppInitializerClasses) {
				// Be defensive: Some servlet containers provide us with invalid classes,
				// no matter what @HandlesTypes says...
				if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) &&
						WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
					try {
						initializers.add((WebApplicationInitializer)
								ReflectionUtils.accessibleConstructor(waiClass).newInstance());
					}
					catch (Throwable ex) {
						throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex);
					}
				}
			}
		}

		if (initializers.isEmpty()) {
			servletContext.log("No Spring WebApplicationInitializer types detected on classpath");
			return;
		}

		servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");
		AnnotationAwareOrderComparator.sort(initializers);
		for (WebApplicationInitializer initializer : initializers) {
		    // 调用下方SpringBootServletInitializer的onStartup方法
			initializer.onStartup(servletContext);
		}
	}
}

三、启动类继承SpringBootServletInitializer

SpringBootServletInitializer是WebApplicationInitializer的实现类,所以会被调用onStartup方法,最终为spring上下文设置一个ServletContext

public void onStartup(ServletContext servletContext) throws ServletException {
		// Logger initialization is deferred in case an ordered
		// LogServletContextInitializer is being used
		this.logger = LogFactory.getLog(getClass());
		// 设置上下文AnnotationConfigServletWebServerApplicationContext.class
		WebApplicationContext rootAppContext = createRootApplicationContext(
				servletContext);
		... //
	}

protected WebApplicationContext createRootApplicationContext(
			ServletContext servletContext) {
		SpringApplicationBuilder builder = createSpringApplicationBuilder();
		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即将构建的SpringApplication对象赋予此属性
		builder.initializers(
				new ServletContextApplicationContextInitializer(servletContext));
		builder.contextClass(AnnotationConfigServletWebServerApplicationContext.class);
		builder = configure(builder);
		builder.listeners(new WebEnvironmentPropertySourceInitializer(servletContext));
		SpringApplication application = builder.build();
		if (application.getAllSources().isEmpty() && AnnotationUtils
				.findAnnotation(getClass(), Configuration.class) != null) {
			application.addPrimarySources(Collections.singleton(getClass()));
		}
		Assert.state(!application.getAllSources().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.addPrimarySources(
					Collections.singleton(ErrorPageFilterConfiguration.class));
		}
		// SpringApplication开始运行
		return run(application);
	}



SpringApplication


public ConfigurableApplicationContext run(String... args) {
	... //
	// 这一步准备执行已经初始化好的ApplicationContextInitializers实现类
	prepareContext(context, environment, listeners, applicationArguments,
					printedBanner);
	refreshContext(context);
	afterRefresh(context, applicationArguments);
	stopWatch.stop();
	... //
}


private void prepareContext(ConfigurableApplicationContext context,
			ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments, Banner printedBanner) {
	context.setEnvironment(environment);
	postProcessApplicationContext(context);
	// 执行已经初始化好的ApplicationContextInitializers实现类
	applyInitializers(context);
    ... //
}
protected void applyInitializers(ConfigurableApplicationContext context) {
		for (ApplicationContextInitializer initializer : getInitializers()) {
			Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(
					initializer.getClass(), ApplicationContextInitializer.class);
			Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
			// 其中ServletContextApplicationContextInitializer负责为      
			//ApplicationContext设置一个ServletContext上下文,在refresh方法执行到onRefresh时,
			//因为上下文已经有了ServletContext上下文,所以不会创建内置tomcat启动
			initializer.initialize(context);
		}
	}

四、ServletWebServerApplicationContext

@Override
	protected void onRefresh() {
		super.onRefresh();
		try {
			createWebServer();
		}
		catch (Throwable ex) {
			throw new ApplicationContextException("Unable to start web server", ex);
		}
	}

如下,因为上下文已经有了ServletContext上下文,所以不会创建内置tomcat启动

private void createWebServer() {
		WebServer webServer = this.webServer;
		ServletContext servletContext = getServletContext();
		// servletContext 不为null,所以不会走这里
		if (webServer == null && servletContext == null) {
			ServletWebServerFactory factory = getWebServerFactory();
			this.webServer = factory.getWebServer(getSelfInitializer());
		}
		else if (servletContext != null) {
			try {
			    // 为ServletContext设置一个DispatcherServlet
				getSelfInitializer().onStartup(servletContext);
			}
			catch (ServletException ex) {
				throw new ApplicationContextException("Cannot initialize servlet context",
						ex);
			}
		}
		initPropertySources();
	}


private ServletContextInitializer getSelfInitializer() {
		return this::selfInitialize;
}
	
private void selfInitialize(ServletContext servletContext) throws ServletException {
		prepareWebApplicationContext(servletContext);
		registerApplicationScope(servletContext);
		WebApplicationContextUtils.registerEnvironmentBeans(getBeanFactory(), servletContext);
		
		// ServletContextInitializer是在解析主启动类@Import注解时,读取spring.factories中的
		// DispatcherServletAutoConfiguration类导入的DispatcherServletRegistrationBean类,
		// DispatcherServletRegistrationBean间接实现了ServletContextInitializer接口
		for (ServletContextInitializer beans : getServletContextInitializerBeans()) {
			beans.onStartup(servletContext);
		}
	}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值