Spring Boot 启动过程


Spring 启动过程,主要分为两部分,第一部分为创建一个 SpringApplication,第二部分为应用的的run过程。

1. 创建Spring应用

创建一个spring应用主要要做了以下工作:

  • 获取web应用类型

    static WebApplicationType deduceFromClasspath() {
    	if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
    			&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
    		return WebApplicationType.REACTIVE;
    	}
    	for (String className : SERVLET_INDICATOR_CLASSES) {
    		if (!ClassUtils.isPresent(className, null)) {
    			return WebApplicationType.NONE;
    		}
    	}
    	return WebApplicationType.SERVLET;
    }
    

    这里获取的目的主要是为后面是否启动Tomcat 容器做准备。

  • 实例化Spring上下文初始化器

    ApplicationContextInitializer 主要作用是初始化ConfigurableApplicationContext 回调的接口,在上下文刷新之前。

    获取的方式是通过Spring工厂加载器SpringFactoryLoader获取的,大致过程如下:

    1. 首先会获取到所有的Spring工厂类全限定名,主要利用了SPI的思想,通过资源加载器获取指定位置下的文件,然后解析文件内容,加载到缓存中。这些都是Spring工厂类。主要代码如下:
    private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
    	Map<String, List<String>> result = cache.get(classLoader);
    	if (result != null) {
    		return result;
    	}
    	
    	result = new HashMap<>();
    	try {
            // FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
    		Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
    		while (urls.hasMoreElements()) {
    			...
    			result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>()).add(factoryImplementationName.trim());
    			...
    		}
    		...
    		cache.put(classLoader, result);
    	}
    	return result;
    }
    
    1. 获取要实例化的初始化器,主要是通过上面解析的工厂类中查找所有的初始化器。根据上面的结果,返回org.springframework.context.ApplicationContextInitializer 类型的所有工厂类

    在这里插入图片描述

    1. 通过反射把这些应用上下文初始化器进行实例化
    private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes,
    			ClassLoader classLoader, Object[] args, Set<String> names) {
    	List<T> instances = new ArrayList<>(names.size());
    	for (String name : names) {
    		try {
    			Class<?> instanceClass = ClassUtils.forName(name, classLoader);
    			Assert.isAssignable(type, instanceClass);
    			Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
    			T instance = (T) BeanUtils.instantiateClass(constructor, args);
    			instances.add(instance);
    		}
    		catch (Throwable ex) {
    			throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex);
    		}
    	}
    	return instances;
    }
    
    1. 然后排序后赋值给Spring应用
    setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    
  • 实例化应用监听器

    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    

    过程和应用上下文初始化器一样,只是获取的类标识为org.springframework.context.ApplicationListener 类别的

  • 添加应用的主类

    if ("main".equals(stackTraceElement.getMethodName())) {
    	return Class.forName(stackTraceElement.getClassName());
    }
    

2. Spring 应用启动过程

应用启动是通过run() 方法执行的,首先创建默认的引导上下文,配置无显设备配置,代码如下:

private DefaultBootstrapContext createBootstrapContext() {
    DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();
    this.bootstrappers.forEach((initializer) -> initializer.intitialize(bootstrapContext));
    return bootstrapContext;
}
configureHeadlessProperty();

2.1 启动应用运行监听器

实例化应用运行监听器,获取方式和上面说的监听器一样,如下:

SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting(bootstrapContext, this.mainApplicationClass);

主要告诉其他监听器,Spring应用正在启动,主类是什么。这里的运行监控器是org.springframework.boot.context.event.EventPublishingRunListener,用来发布事件用的,会调用多播器发布ApplicationStartingEvent 事件。

// 初始化时创建了一个多播器
public EventPublishingRunListener(SpringApplication application, String[] args) {
    this.application = application;
    this.args = args;
    this.initialMulticaster = new SimpleApplicationEventMulticaster();
    for (ApplicationListener<?> listener : application.getListeners()) {
        this.initialMulticaster.addApplicationListener(listener);
    }
}
// 发布事件
public void starting(ConfigurableBootstrapContext bootstrapContext) {
	this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(bootstrapContext, this.application, this.args));
}

2.2 准备环境

ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);

会根据环境不同,创建不同的环境对象,然后发布一个ApplicationEnvironmentPreparedEvent事件。

listeners.environmentPrepared(bootstrapContext, environment);

public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {
this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(bootstrapContext, this.application, this.args, environment));
}

protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
    if (this.addConversionService) {
        ConversionService conversionService = ApplicationConversionService.getSharedInstance();
        //添加格式转换组件
        environment.setConversionService((ConfigurableConversionService) conversionService);
    }
    configurePropertySources(environment, args);
    configureProfiles(environment, args);
}
//环境用了哪个配置
environment.setActiveProfiles(StringUtils.toStringArray(profiles));
//将环境绑定到应用上
bindToSpringApplication(environment);
//配置属性源添加到环境中
ConfigurationPropertySources.attach(environment);

2.3 打印banner

2.4 创建上下文

根据web应用类型创建应用上下文AnnotationConfigServletWebServerApplicationContext。这里就是spring上下文启动过程。

context = createApplicationContext();
context.setApplicationStartup(this.applicationStartup);

如下图所示:

在这里插入图片描述

public AnnotationConfigServletWebServerApplicationContext() {
    this.reader = new AnnotatedBeanDefinitionReader(this);
    this.scanner = new ClassPathBeanDefinitionScanner(this);
}

2.5 准备上下文

//1. 把环境设置到容器中
context.setEnvironment(environment);
postProcessApplicationContext(context);
//2: 循环调用AppplicationInitnazlier 进行容器初始化工作
applyInitializers(context);
//3:发布容器上下文准备完成事件
listeners.contextPrepared(context);
bootstrapContext.close(context);
if (this.logStartupInfo) {
    logStartupInfo(context.getParent() == null);
    logStartupProfileInfo(context);
}
//4:注册关于springboot特性的相关单例Bean
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (this.lazyInitialization) {
    context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
//5:发布容器上下文加载完毕事件
listeners.contextLoaded(context);

接下来是刷新上下文,在分析刷新上下文之前,先看看主配值上都有哪些配置。

3. @SpringBootApplication

主要的注解有@ComponentScan、@EnableAutoConfiguration、@SpringBootConfiguration

@ComponentScan 我们在bean生命周期中解析过,这里不做赘述。

主要看看@EnableAutoConfiguration 自动配置注解的作用。

@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration

@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage

通过bean的解析过程中,我们知道AutoConfigurationImportSelector.classAutoConfigurationPackages.Registrar.class 是往容器中添加组件。

根据前面文章可知@Import注解实在ConfigurationClassParser 配置类解析其中置行的,我们看看代码置行逻辑,如下:

for (SourceClass candidate : importCandidates) {
    // ImportSelector
	if (candidate.isAssignable(ImportSelector.class)) {
		ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
				this.environment, this.resourceLoader, this.registry);
        // DeferredImportSelector 会执行handle方法
		if (selector instanceof DeferredImportSelector) {
			this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
		}
        // 非DeferredImportSelector 会执行selectImports方法
		else {
			String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
		}
	}
    // ImportBeanDefinitionRegistrar 会注册到解析策略中,单独解析bean
	else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
		Class<?> candidateClass = candidate.loadClass();
		ImportBeanDefinitionRegistrar registrar =
				ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
						this.environment, this.resourceLoader, this.registry);
		configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
	}
	else {
	}
}

3.1 AutoConfigurationImportSelector

public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
    AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
        .getAutoConfigurationEntry(annotationMetadata);
}

protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
   	// 获取候选的配置类
    List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
    // 删除掉重复的,因为不同jar下可能加载了重复的
    configurations = removeDuplicates(configurations);
    
    fireAutoConfigurationImportEvents(configurations, exclusions);
    return new AutoConfigurationEntry(configurations, exclusions);
}

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
                                                                         getBeanClassLoader());
    return configurations;
}

SpringFactoriesLoader.loadFactoryNames 是不是很熟悉,和应用上下文初始化器和应用监听器加载过程是不是一样。使用META-INF/spring.factories 位置的配置文件,加载自动配置文件下的自动配置类,key为org.springframework.boot.autoconfigure.EnableAutoConfiguration ,这下面的自动配置类有很多,具体如下图所示:

在这里插入图片描述

我们来看看这些配置类是怎么工作的。

举一个例子来说明下:

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(KafkaTemplate.class)
// 添加kafka属性配置,即yaml文件中的配置
@EnableConfigurationProperties(KafkaProperties.class)
@Import({ KafkaAnnotationDrivenConfiguration.class, KafkaStreamsAnnotationDrivenConfiguration.class })
public class KafkaAutoConfiguration {

	private final KafkaProperties properties;

	public KafkaAutoConfiguration(KafkaProperties properties) {
		this.properties = properties;
	}

	@Bean
	@ConditionalOnMissingBean(KafkaTemplate.class)
	public KafkaTemplate<?, ?> kafkaTemplate(ProducerFactory<Object, Object> kafkaProducerFactory,
			ProducerListener<Object, Object> kafkaProducerListener,
			ObjectProvider<RecordMessageConverter> messageConverter) {
		KafkaTemplate<Object, Object> kafkaTemplate = new KafkaTemplate<>(kafkaProducerFactory);
		messageConverter.ifUnique(kafkaTemplate::setMessageConverter);
		kafkaTemplate.setProducerListener(kafkaProducerListener);
		kafkaTemplate.setDefaultTopic(this.properties.getTemplate().getDefaultTopic());
		return kafkaTemplate;
	}
}

AutoConfigurationImportSelector 为我们容器中注册了那些组件,然后根据maven依赖导入的jar包,根据条件装配来指定哪些组件起作用,哪些组件不起作用。

我们来分析一下,Tomcat的启动过程吧。

@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication
@EnableConfigurationProperties(ServerProperties.class)
public class EmbeddedWebServerFactoryCustomizerAutoConfiguration {

	/**
	 * Nested configuration if Tomcat is being used.
	 */
	@Configuration(proxyBeanMethods = false)
	@ConditionalOnClass({ Tomcat.class, UpgradeProtocol.class })
	public static class TomcatWebServerFactoryCustomizerConfiguration {

		@Bean
		public TomcatWebServerFactoryCustomizer tomcatWebServerFactoryCustomizer(Environment environment,
				ServerProperties serverProperties) {
			return new TomcatWebServerFactoryCustomizer(environment, serverProperties);
		}

	}
}

TomcatWebServerFactoryCustomizer tomcat服务工厂定制器通过ServerProperties 的定制化tomcat容器。

4. 刷新上下文之Tomcat过程

这里和非web刷新上下文基本一样,我们主要看看Tomcat的启动过程吧。ServletWebServerApplicationContext 上下文中启动tomcat。

protected void onRefresh() {
    super.onRefresh();
    try {
        createWebServer();
    }
    catch (Throwable ex) {
        throw new ApplicationContextException("Unable to start web server", ex);
    }
}
private void createWebServer() {
    WebServer webServer = this.webServer;
    ServletContext servletContext = getServletContext();
    if (webServer == null && servletContext == null) {
        StartupStep createWebServer = this.getApplicationStartup().start("spring.boot.webserver.create");
        // 获取server工厂类
        ServletWebServerFactory factory = getWebServerFactory();
        createWebServer.tag("factory", factory.getClass().toString());
        // 创建web容器
        this.webServer = factory.getWebServer(getSelfInitializer());
        createWebServer.end();
        getBeanFactory().registerSingleton("webServerGracefulShutdown",
                                           new WebServerGracefulShutdownLifecycle(this.webServer));
        getBeanFactory().registerSingleton("webServerStartStop",
                                           new WebServerStartStopLifecycle(this, this.webServer));
    }
    else if (servletContext != null) {
        try {
            getSelfInitializer().onStartup(servletContext);
        }
        catch (ServletException ex) {
            throw new ApplicationContextException("Cannot initialize servlet context", ex);
        }
    }
    initPropertySources();
}

在创建web服务时,会先获取ServletWebServerFactory ,这里时tomcatServletWebServerFactory,如下图所示:

在这里插入图片描述

代码如下:

protected ServletWebServerFactory getWebServerFactory() {
    // Use bean names so that we don't consider the hierarchy
    String[] beanNames = getBeanFactory().getBeanNamesForType(ServletWebServerFactory.class);
    ...
    return getBeanFactory().getBean(beanNames[0], ServletWebServerFactory.class);
}

通过类型来获取beanName,通过beanName来创建实例。

@Configuration(proxyBeanMethods = false)
class ServletWebServerFactoryConfiguration {

	@Configuration(proxyBeanMethods = false)
	@ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class })
	@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
	static class EmbeddedTomcat {

        // 引入的tomcatServletWebServerFactory
		@Bean
		TomcatServletWebServerFactory tomcatServletWebServerFactory(
				ObjectProvider<TomcatConnectorCustomizer> connectorCustomizers,
				ObjectProvider<TomcatContextCustomizer> contextCustomizers,
				ObjectProvider<TomcatProtocolHandlerCustomizer<?>> protocolHandlerCustomizers) {
			TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
			factory.getTomcatConnectorCustomizers()
					.addAll(connectorCustomizers.orderedStream().collect(Collectors.toList()));
			factory.getTomcatContextCustomizers()
					.addAll(contextCustomizers.orderedStream().collect(Collectors.toList()));
			factory.getTomcatProtocolHandlerCustomizers()
					.addAll(protocolHandlerCustomizers.orderedStream().collect(Collectors.toList()));
			return factory;
		}

	}
}

创建tomcatServletWebServerFactory 会引入WebServerFactoryCustomizerBeanPostProcessor进行定制化操作,这个组件的引入是通过 ServletWebServerFactoryAutoConfiguration 自动配置过程中注入的。

自动配置过程中,主要引入了两个配置类,EmbeddedWebServerFactoryCustomizerAutoConfigurationServletWebServerFactoryAutoConfiguration ,如下图所示:

@Configuration(proxyBeanMethods = false)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@ConditionalOnClass(ServletRequest.class)
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(ServerProperties.class)
@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
		ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
		ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
		ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
public class ServletWebServerFactoryAutoConfiguration {

    // 创建ServletWebServerFactoryCustomizer
	@Bean
	public ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(ServerProperties serverProperties,
			ObjectProvider<WebListenerRegistrar> webListenerRegistrars) {
		return new ServletWebServerFactoryCustomizer(serverProperties,
				webListenerRegistrars.orderedStream().collect(Collectors.toList()));
	}
    
    // 创建TomcatServletWebServerFactoryCustomizer
    @Bean
	@ConditionalOnClass(name = "org.apache.catalina.startup.Tomcat")
	public TomcatServletWebServerFactoryCustomizer tomcatServletWebServerFactoryCustomizer(
			ServerProperties serverProperties) {
		return new TomcatServletWebServerFactoryCustomizer(serverProperties);
	}
    
    // 添加后置处理器
	public static class BeanPostProcessorsRegistrar implements ImportBeanDefinitionRegistrar, BeanFactoryAware {

		private ConfigurableListableBeanFactory beanFactory;

		@Override
		public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
			if (beanFactory instanceof ConfigurableListableBeanFactory) {
				this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
			}
		}

		@Override
		public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
				BeanDefinitionRegistry registry) {
			if (this.beanFactory == null) {
				return;
			}
            // 注册了webServerFactoryCustomizerBeanPostProcessor
			registerSyntheticBeanIfMissing(registry, "webServerFactoryCustomizerBeanPostProcessor",
					WebServerFactoryCustomizerBeanPostProcessor.class,
					WebServerFactoryCustomizerBeanPostProcessor::new);
			registerSyntheticBeanIfMissing(registry, "errorPageRegistrarBeanPostProcessor",
					ErrorPageRegistrarBeanPostProcessor.class, ErrorPageRegistrarBeanPostProcessor::new);
		}

		private <T> void registerSyntheticBeanIfMissing(BeanDefinitionRegistry registry, String name,
				Class<T> beanClass, Supplier<T> instanceSupplier) {
			if (ObjectUtils.isEmpty(this.beanFactory.getBeanNamesForType(beanClass, true, false))) {
				RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass, instanceSupplier);
				beanDefinition.setSynthetic(true);
				registry.registerBeanDefinition(name, beanDefinition);
			}
		}

	}
}

WebServerFactoryCustomizerBeanPostProcessor去获取WebServerFactoryCustomizer

private void postProcessBeforeInitialization(WebServerFactory webServerFactory) {
    //获取定制器
   LambdaSafe.callbacks(WebServerFactoryCustomizer.class, getCustomizers(), webServerFactory)
         .withLogger(WebServerFactoryCustomizerBeanPostProcessor.class)
      	// 循环调用定制化过程
         .invoke((customizer) -> customizer.customize(webServerFactory));
}
private Collection<WebServerFactoryCustomizer<?>> getWebServerFactoryCustomizerBeans() {
    return (Collection) this.beanFactory.getBeansOfType(WebServerFactoryCustomizer.class, false, false).values();
}

在这里插入图片描述

定制化工作完成后,会进入tomcat创建和启动过程,如下:

public WebServer getWebServer(ServletContextInitializer... initializers) {
    if (this.disableMBeanRegistry) {
        Registry.disableRegistry();
    }
    Tomcat tomcat = new Tomcat();
    ...
    return getTomcatWebServer(tomcat);
}
public TomcatWebServer(Tomcat tomcat, boolean autoStart, Shutdown shutdown) {
    Assert.notNull(tomcat, "Tomcat Server must not be null");
    this.tomcat = tomcat;
    this.autoStart = autoStart;
    this.gracefulShutdown = (shutdown == Shutdown.GRACEFUL) ? new GracefulShutdown(tomcat) : null;
    initialize();
}
private void initialize() throws WebServerException {
    synchronized (this.monitor) {
        try {
            ...
            // Start the server to trigger initialization listeners
            this.tomcat.start();
            ...
        }
    }
}

5. Spring boot 启动过程图解

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值