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
获取的,大致过程如下:- 首先会获取到所有的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; }
- 获取要实例化的初始化器,主要是通过上面解析的工厂类中查找所有的初始化器。根据上面的结果,返回
org.springframework.context.ApplicationContextInitializer
类型的所有工厂类
- 通过反射把这些应用上下文初始化器进行实例化
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; }
- 然后排序后赋值给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.class
和 AutoConfigurationPackages.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
自动配置过程中注入的。
自动配置过程中,主要引入了两个配置类,EmbeddedWebServerFactoryCustomizerAutoConfiguration
和 ServletWebServerFactoryAutoConfiguration
,如下图所示:
@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();
...
}
}
}