SpringBoot启动流程源码分析(2)
1、启动引导类
大部分时候,SpringBoot应用主要通过在引导类调用SpringApplication的静态run方法启动,同时将引导类注册为配置源。比如下面是一个SpringMVC的Web应用,引导类是WebMVCBootstrap,和命令行参数args作为SpringApplication静态run方法的参数,用于构建SpringApplication对象和运行SpringBoot应用。
// 引导类添加@SpringBootApplication注解作为配置源,同时开启自动装配、缺省包路径扫描 @SpringBootApplication public class WebMVCBootstrap { public static void main(String[] args) { // 引导类WebMVCBootstrap.class注册为主要配置源 SpringApplication.run(WebMVCBootstrap.class,args); } }
如果引导类作为配置源,一般情况下都会标记@SpringBootApplication或@EnableAutoConfiguration等注解以开启自动装配。这里的配置源,指的是@Configuration或其派生注解的类,即Spring的Configuration配置类。
2、创建SpringApplication对象
跟踪SpringApplication的静态run方法,发现SpringBootApplication还提供了一个重载的静态run方法,可以指定多个、不同类型或不同来源的配置类。
public class SpringApplication { ... public static ConfigurableApplicationContext run(Class<?> primarySource, String... args){ // 调用重载的静态run方法,第一个参数为数组,可以指定多个Configuration配置类 return run(new Class<?>[] { primarySource }, args); } ... public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) { // 首先,根据指定的配置源创建SpringApplication对象 // 接着,SpringApplication对象调用对象run方法运行应用 return new SpringApplication(primarySources).run(args); } ... }
创建SpringApplication对象,最终调用的是两个参数的构造方法,其主要工作是初始化资源加载器resourceLoader、主要配置源primarySources、推断web应用类型webApplicationType(后面很多地方会用到)、加载初始化器initializers、加载监听器listeners以及推断应用主类mainApplicationClass。
public class SpringApplication { ... public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { // 资源加载器resourceLoader:当前为null this.resourceLoader = resourceLoader; // 主要配置源primarySources:只有一个元素WebMVCBootstrap.class this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); // 推断web应用类型webApplicationType:推断为WebApplicationType.SERVLET // 由于项目依赖了spring-boot-starter-web this.webApplicationType = WebApplicationType.deduceFromClasspath(); // 加载并设置上下文初始化器initializers:7个 setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); // 加载并设置上下文事件监听器listeners:11个 // 其中包括加载application.yaml的监听器ConfigFileApplicationListener setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); // 应用引导类mainApplicationClass:推断为WebMVCBootstrap.class this.mainApplicationClass = deduceMainApplicationClass(); } ... }
2.1、推断web应用类型
SpringBoot根据当前应用中是否引入了对应的依赖类库(核心类)来推断Web应用类型。首先,如果类加载器中存在DispatcherHandler类且不存在DispatcherServlet类和ServletContainer类,则推断为基于REACTIVE的Web应用即WebFlux;其次,如果不存在Servlet类或ConfigurableWebApplicationContext类,则推断为非Web应用;最后,剩下的默认为是基于Servlet的Web应用,包括WebMVC或Jersey。
public enum WebApplicationType { NONE, // 非Web应用 SERVLET, // 基于SERVLET的Web应用:WebMVC或Jersey REACTIVE; // 基于REACTIVE的Web应用:WebFlux // SERVLET核心依赖:WEBMVC、JERSEY private static final String[] SERVLET_INDICATOR_CLASSES = { "javax.servlet.Servlet", "org.springframework.web.context.ConfigurableWebApplicationContext" }; // WEBMVC核心依赖 private static final String WEBMVC_INDICATOR_CLASS = "org.springframework.web.servlet.DispatcherServlet"; // WEBFLUX核心依赖 private static final String WEBFLUX_INDICATOR_CLASS = "org.springframework.web.reactive.DispatcherHandler"; // JERSEY核心依赖 private static final String JERSEY_INDICATOR_CLASS = "org.glassfish.jersey.servlet.ServletContainer"; ... static WebApplicationType deduceFromClasspath() { // 存在WEBFLUX依赖,且没有WEBMVC以及JERSEY依赖:REACTIVE的Web应用 if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null) && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) { return WebApplicationType.REACTIVE; } // 不存在SERVLET相关的核心依赖:非Web应用 for (String className : SERVLET_INDICATOR_CLASSES) { if (!ClassUtils.isPresent(className, null)) { return WebApplicationType.NONE; } } // 剩下的:只能是WEBMVC或JERSEY等基于SERVLET的Web应用 return WebApplicationType.SERVLET; } ... }
2.2、初始化initializers和listeners
初始化器initializers和监听器listeners都是使用了Spring的扩展机制(基于SPI)进行加载。初始化器和监听器都以键值对形式声明在META-INF/spring.factories文件中,多个使用逗号分隔,spring.factories文件主要分布在spring-boot和spring-boot-autoconfigure模块下。这一步骤总共加载了7个初始化器和11个监听器。
// 加载spring.factories文件声明的类对象 private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) { return getSpringFactoriesInstances(type, new Class<?>[] {}); } // 加载spring.factories文件声明的类对象 private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) { ClassLoader classLoader = getClassLoader(); // SpringFactoriesLoader从META-INF/spring.factories中加载指定类型为type的类名称 // 以type为key,names即格式化后的value类名集合 Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader)); // 实例化加载到的类,createSpringFactoriesInstances方法使用类的默认构造方法创建对象实例 List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names); // 排序 AnnotationAwareOrderComparator.sort(instances); return instances; }
spring-boot和spring-boot-autoconfigure模块下spring.factories文件中声明的初始化器
... # spring-boot模块 # Application Context Initializers org.springframework.context.ApplicationContextInitializer=\ org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\ org.springframework.boot.context.ContextIdApplicationContextInitializer,\ org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\ org.springframework.boot.rsocket.context.RSocketPortInfoApplicationContextInitializer,\ org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer ... # spring-boot-autoconfigure模块 # Initializers org.springframework.context.ApplicationContextInitializer=\ org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\ org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener ...
spring-boot和spring-boot-autoconfigure模块下spring.factories文件中声明的监听器
... # spring-boot模块 # Application Listeners org.springframework.context.ApplicationListener=\ org.springframework.boot.ClearCachesApplicationListener,\ org.springframework.boot.builder.ParentContextCloserApplicationListener,\ org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\ org.springframework.boot.context.FileEncodingApplicationListener,\ org.springframework.boot.context.config.AnsiOutputApplicationListener,\ org.springframework.boot.context.config.ConfigFileApplicationListener,\ org.springframework.boot.context.config.DelegatingApplicationListener,\ org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,\ org.springframework.boot.context.logging.LoggingApplicationListener,\ org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener ... # spring-boot-autoconfigure模块 # Application Listeners org.springframework.context.ApplicationListener=\ org.springframework.boot.autoconfigure.BackgroundPreinitializer ...
2.3、推断应用主类
SpringBoot通过遍历解析方法栈中的元素,其方法是否是main方法来推断应用主类。刚启动SpringBoot应用,此时方法栈中的方法元素不多,含有main方法的一般不会有多于1个,基本上就是引导类,也就是WebMVCBootstrap类。准确的说,应该是获取运行时方法栈中,第一个含有main方法的元素对应的类作为应用主类mainApplicationClass。
private Class<?> deduceMainApplicationClass() { try { // 从运行时方法栈中判断元素是否含有main方法来推断 StackTraceElement[] stackTrace = new RuntimeException().getStackTrace(); for (StackTraceElement stackTraceElement : stackTrace) { // 如果方法栈中的元素,其方法是main方法 if ("main".equals(stackTraceElement.getMethodName())) { // 则获取元素对应的类对象返回作为应用主类mainApplicationClass return Class.forName(stackTraceElement.getClassName()); } } } catch (ClassNotFoundException ex) { // Swallow and continue } return null; }
通过debug工具,查看运行时方法栈,发现共有6个元素,含有main方法的只有WebMVCBootstrap类
stackTrace = {StackTraceElement[6]@1183} 0 = {StackTraceElement@1188} "org.springframework.boot.SpringApplication.deduceMainApplicationClass(SpringApplication.java:279)" 1 = {StackTraceElement@1198} "org.springframework.boot.SpringApplication.<init>(SpringApplication.java:274)" 2 = {StackTraceElement@1208} "org.springframework.boot.SpringApplication.<init>(SpringApplication.java:253)" 3 = {StackTraceElement@1218} "org.springframework.boot.SpringApplication.run(SpringApplication.java:1237)" 4 = {StackTraceElement@1228} "org.springframework.boot.SpringApplication.run(SpringApplication.java:1226)" 5 = {StackTraceElement@1240} "com.fandou.coffee.springboot.web.WebMVCBootstrap.main(WebMVCBootstrap.java:9)"
SpringApplication对象创建完成,接下来开始运行SpringApplication对象的对象run方法,进入运行阶段。
3、运行SpringApplication
SpringApplication运行阶段可以划分为应用开始启动、准备环境变量、创建和初始化上下文、准备应用上下文、应用启动、应用就绪等6个步骤。涉及的内容包括创建生命周期事件监听器listeners、封装命令行参数applicationArguments、创建和加载环境变量environment、打印banner、创建应用上下文、加载异常报告器、初始化应用上下文、加载主要配置源、刷新应用上下文、运行命令行和应用运行期执行任务,以及触发和传播相关的生命周期事件。其中,application.yaml配置文件在准备环境变量environment步骤中被加载解析;自动装配或者配置类相关注解的解析以及嵌入式Web服务器的启动等,均在刷新应用上下文步骤完成,该阶段属于所有Spring应用的必经阶段;SpringBoot生命周期事件在各个步骤中被适时触发和传播。
public ConfigurableApplicationContext run(String... args) { ... // 应用上下文对象 ConfigurableApplicationContext context = null; ... // 加载SpringBoot生命周期事件监听器:用于监听和触发SpringBoot生命周期事件 // 同样从META-INF/spring.factories文件中加载,目前仅有1个 SpringApplicationRunListeners listeners = getRunListeners(args); // 1、触发ApplicationStartingEvent事件 listeners.starting(); try { // 封装应用启动传入的命令行参数 ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); // 准备环境:包括系统变量、系统属性 // 2、期间将触发ApplicationEnvironmentPreparedEvent事件加载application.yaml配置 ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); configureIgnoreBeanInfo(environment); // 打印Banner Banner printedBanner = printBanner(environment); // 根据web应用类型创建应用上下文 context = createApplicationContext(); // 从META-INF/spring.factories文件中加载创建异常报告器 exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context); // 准备应用上下文:初始化上下文并加载主要配置源 // 3、期间将触发ApplicationContextInitializedEvent和ApplicationPreparedEvent事件 prepareContext(context, environment, listeners, applicationArguments, printedBanner); // 刷新应用上下文:解析自动装配或者配置类相关注解,以及启动嵌入式Web服务器的等,注册bean定义 // 4、期间将触发ContextRefreshedEvent事件 refreshContext(context); // 刷新后回调:目前空实现,留待子类或后续扩展 afterRefresh(context, applicationArguments); ... // 5、发布ApplicationStartedEvent事件以及AvailabilityChangeEvent事件 listeners.started(context); // 调用ApplicationRunner和CommandLineRunner任务 callRunners(context, applicationArguments); } catch (Throwable ex) { ... } try { // 6、发布ApplicationReadyEvent事件AvailabilityChangeEvent事件 listeners.running(context); } catch (Throwable ex) { ... } return context; }
3.1、开始启动应用
从启动引导类开始,从创建SpringApplication对象,一直到创建SpirngBoot生命周期事件监听器并发布ApplicationStartingEvent事件为止,都可以认为是开始启动应用阶段的工作。创建SpringApplication对象的源码前面已经分析过,下面开始分析SpringBoot生命周期事件监听器的创建。
- 加载SpringBoot生命周期事件监听器
跟踪SpringApplication#getRunListeners方法的源码,SpringBoot生命周期事件监听器的也是使用spring的扩展机制创建的,和创建SpringApplication对象时获取上下文初始化器initializers是一样的机制,都是从META-INF/spring.factories文件中加载并创建。
private SpringApplicationRunListeners getRunListeners(String[] args) { Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class }; // 创建SpringApplicationRunListeners对象,它内部封装了从META-INF/spring.factories文件中 // 加载的EventPublishingRunListener实例 return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args)); }
配置在spring-boot模块下的SpringApplicationRunListener,目前只有1个实例,用来监听并发布事件。
# Run Listeners org.springframework.boot.SpringApplicationRunListener=\ org.springframework.boot.context.event.EventPublishingRunListener
- 触发首个SpringBoot事件:ApplicationStartingEvent事件
listeners集合中存储的是EventPublishingRunListener的对象实例,目前只有一个元素。
class SpringApplicationRunListeners { ... // 触发ApplicationStartingEvent事件 void starting() { for (SpringApplicationRunListener listener : this.listeners) { // listener是EventPublishingRunListener的实例 listener.starting(); } } ... }
跟踪查看EventPublishingRunListener#starting方法,其内部将SpringApplication对象封装为事件源,然后调用事件广播器initialMulticaster广播事件,initialMulticaster是SimpleApplicationEventMulticaster对象实例。
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered { ... // 事件广播器 private final SimpleApplicationEventMulticaster initialMulticaster; ... // 广播ApplicationStartingEvent事件,SpringApplication对象application被封装为事件源 // 而application对象内部在创建时,通过Spring的加载机制从META-INF/spring.factories文件中加载 // 持有了SpringBoot内置的11事件监听器,包括用于加载application.yaml配置文件 // 的ConfigFileApplicationListener。自定义监听器也可以使用这种方式。 @Override public void starting() { this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args)); } ... }
继续跟踪事件广播器SimpleApplicationEventMulticaster#initialMulticaster#的源码,其直接遍历获取注册到事件源即SpringApplication对象中对当前事件感兴趣的监听器,然后调用监听器的onApplicationEvent完成事件的传播。
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster { ... // 广播事件 @Override public void multicastEvent(ApplicationEvent event) { // 调用重载方法multicastEvent广播事件 multicastEvent(event, resolveDefaultEventType(event)); } // 广播事件 @Override public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) { ... // 遍历注册到事件源中对事件感兴趣的监听器: // getApplicationListeners方法从事件源即SpringApplication对象中获取事件监听器 for (ApplicationListener<?> listener : getApplicationListeners(event, type)) { ... // 调用监听器 invokeListener(listener, event); ... } } // 调用监听器:提供事件传播控制机制 protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) { ErrorHandler errorHandler = getErrorHandler(); if (errorHandler != null) { // 可以用于控制在出现异常时中断或继续对事件在后续的监听器中传播 try { doInvokeListener(listener, event); } catch (Throwable err) { errorHandler.handleError(err); } } else { // 有错误直接抛异常 doInvokeListener(listener, event); } } // 调用具体的监听器 @SuppressWarnings({"rawtypes", "unchecked"}) private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) { try { // 最终调用了具体的监听器的onApplicationEvent方法,完成事件的广播 listener.onApplicationEvent(event); } catch (ClassCastException ex) { ... } } ... }
应用开始启动了,接下来进入环境准备阶段。
3.2、准备环境变量
准备环境变量主要包括封装命令行参数applicationArguments以及创建和初始化环境变量environment以及触发ApplicationEnvironmentPreparedEvent事件,事件的发布将触发加载application.yaml配置文件。
- 封装命令行参数applicationArguments
对于传递进来的命令行参数args,被封装为ApplicationArguments对象的属性source,source是SimpleCommandLinePropertySource实例对象。ApplicationArguments对象接下来,也会用于构建环境变量environment。
public DefaultApplicationArguments(String... args) { Assert.notNull(args, "Args must not be null"); // Source类继承SimpleCommandLinePropertySource this.source = new Source(args); this.args = args; }
- 创建和初始化环境变量environment
在此步骤中,SpringBoot创建了环境变量environment之后,触发ApplicationEnvironmentPreparedEvent事件,接着将环境变量environment绑定到SpringApplication上。这个步骤主要关注创建环境变量方法以及ApplicationEnvironmentPreparedEvent事件触发加载application.yaml文件两个部分。
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) { // 根据web应用类型webApplicationType创建环境变量对象environment: // SERVLET:本示例实际创建的即是StandardServletEnvironment对象 // REACTIVE:StandardReactiveWebEnvironment // NONE:StandardEnvironment ConfigurableEnvironment environment = getOrCreateEnvironment(); // 配置环境变量: // 配置转换对象、封装保存main方法传递进来的args参数、配置spring.profiles.active参数 configureEnvironment(environment, applicationArguments.getSourceArgs()); ConfigurationPropertySources.attach(environment); // 触发ApplicationEnvironmentPreparedEvent事件: // 监听器ConfigFileApplicationListener将会加载application.yaml文件 listeners.environmentPrepared(environment); // 将环境变量到SpringApplication对象上 bindToSpringApplication(environment); // 转换为标准的环境变量对象实例,如果有必要的话 if (!this.isCustomEnvironment) { environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment, deduceEnvironmentClass()); } ConfigurationPropertySources.attach(environment); return environment; }
看以下创建环境变量的getOrCreateEnvironment方法。getOrCreateEnvironment方法逻辑很简单,就是根据web应用类型webApplicationType分别创建不同的环境变量对象。其中StandardEnvironment继承扩展了抽象的环境类AbstractEnvironment,是StandardServletEnvironment和StandardReactiveWebEnvironment的父类。
private ConfigurableEnvironment getOrCreateEnvironment() { if (this.environment != null) { return this.environment; } // 根据web应用类型webApplicationType分别创建不同的环境变量对象 switch (this.webApplicationType) { case SERVLET: // 当前示例创建的是StandardServletEnvironment return new StandardServletEnvironment(); case REACTIVE: return new StandardReactiveWebEnvironment(); default: return new StandardEnvironment(); } }
通过跟踪源码,三种环境变量类都没有默认构造方法,即都使用其抽象环境类AbstractEnvironment的默认构造方法来创建实例。AbstractEnvironment的默认构造方法中调用了由子类覆盖的customizePropertySources方法。可以发现SpringBoot在创建环境变量时,使用了模板方法设计模式来解决不同环境下创建环境变量可能存在的差异问题。
public abstract class AbstractEnvironment implements ConfigurableEnvironment { ... public AbstractEnvironment() { // 调用子类的自定义属性方法 customizePropertySources(this.propertySources); } // 由子类实现 protected void customizePropertySources(MutablePropertySources propertySources) { } ... }
StandardEnvironment是StandardServletEnvironment和StandardReactiveWebEnvironment的父类,StandardEnvironment的customizePropertySources方法中负责加载标准的属性来源:系统环境systemEnvironment(如配置的JAVA_HOME、CLASSPATH等)和系统属性systemProperties(如java.version、file.encoding、line.separator等)。
public class StandardEnvironment extends AbstractEnvironment { ... @Override protected void customizePropertySources(MutablePropertySources propertySources) { // 获取系统属性并保存 propertySources.addLast( new PropertiesPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties())); // 获取系统变量并保存 propertySources.addLast( new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment())); } }
StandardServletEnvironment类的customizePropertySources方法则额外创建用于保存servletContextInitParams、servletConfigInitParams、jndiProperties等属性来源的属性源对象。
public class StandardServletEnvironment extends StandardEnvironment implements ConfigurableWebEnvironment { ... @Override protected void customizePropertySources(MutablePropertySources propertySources) { // 额外创建用于后续保存servletContextInitParams、servletConfigInitParams、jndiProperties // 等相关的属性对象 propertySources.addLast(new StubPropertySource(SERVLET_CONFIG_PROPERTY_SOURCE_NAME)); propertySources.addLast(new StubPropertySource(SERVLET_CONTEXT_PROPERTY_SOURCE_NAME)); if (JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable()) { propertySources.addLast(new JndiPropertySource(JNDI_PROPERTY_SOURCE_NAME)); } // 然后父类的customizePropertySources创建并加载系统变量和系统属性 super.customizePropertySources(propertySources); } ... }
不过StandardReactiveWebEnvironment类没有实现customizePropertySources方法,所以目前它和StandardEnvironment是一样的。
环境变量environment创建成功,对环境变量environment进行了一些初始化,比如封装命令行参数、spring.profiles.active等,之后listeners调用environmentPrepared方法触发了ApplicationEnvironmentPreparedEvent事件。
通过前面对触发ApplicationStartingEvent事件的源码跟踪,事件最终被注册到SpringApplication对象上的监听器接收,由监听器的onApplicationEvent方法处理。SpringApplication对象上注册的监听器当中,有一个ConfigFileApplicationListener监听器,其监听了ApplicationEnvironmentPreparedEvent事件,当ApplicationEnvironmentPreparedEvent事件触发时,它将加载application.yaml配置文件的内容到环境变量中。
public class ConfigFileApplicationListener implements EnvironmentPostProcessor, SmartApplicationListener, Ordered { ... // 事件监听接口方法 @Override public void onApplicationEvent(ApplicationEvent event) { // 监听和处理ApplicationEnvironmentPreparedEvent事件 if (event instanceof ApplicationEnvironmentPreparedEvent) { onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent) event); } ... } // 处理ApplicationEnvironmentPreparedEvent事件 private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) { // 从META-INF/spring.factories中加载EnvironmentPostProcessor实例,如果有的话 List<EnvironmentPostProcessor> postProcessors = loadPostProcessors(); // ConfigFileApplicationListener本身也实现了EnvironmentPostProcessor接口 postProcessors.add(this); AnnotationAwareOrderComparator.sort(postProcessors); for (EnvironmentPostProcessor postProcessor : postProcessors) { // 调用ConfigFileApplicationListener的postProcessEnvironment方法 // 加载application.yaml配置文件 postProcessor.postProcessEnvironment(event.getEnvironment(), event.getSpringApplication()); } } ... // 加载application.yaml配置文件 @Override public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { // 调用addPropertySources方法加载application.yaml配置文件 addPropertySources(environment, application.getResourceLoader()); } // 加载application.yaml配置文件 protected void addPropertySources(ConfigurableEnvironment environment, ResourceLoader resourceLoader) { RandomValuePropertySource.addToEnvironment(environment); // 使用内部类Loader加载配置文件 new Loader(environment, resourceLoader).load(); } ... // 内部类:内部使用属性源加载器加载配置文件 private class Loader { ... // 初始化 Loader(ConfigurableEnvironment environment, ResourceLoader resourceLoader) { ... // 加载并创建MEAT-INF/spring.factories中声明的属性源加载器 this.propertySourceLoaders = SpringFactoriesLoader.loadFactories(PropertySourceLoader.class, getClass().getClassLoader()); } ... // 最终调用load方法加载 private void load(String location, String name, Profile profile, DocumentFilterFactory filterFactory, DocumentConsumer consumer) { if (!StringUtils.hasText(name)) { // 调用PropertiesPropertySourceLoader或YamlPropertySourceLoader加载 for (PropertySourceLoader loader : this.propertySourceLoaders) { if (canLoadFileExtension(loader, location)) { load(loader, location, profile, filterFactory.getDocumentFilter(profile), consumer); return; } } ... } ... } } ... }
最终,ConfigFileApplicationListener处理器通过内部类Loader来加载application.yaml配置文件。而具体加载和解析配置文件的工作则是从由MEAT-INF/spring.factories中声明的属性源加载器完成,属性源加载器一共有2个,其中PropertiesPropertySourceLoader用于加载解析.properties和xml配置文件,YamlPropertySourceLoader则用于加载yaml/yml等后缀的配置文件
# PropertySource Loaders org.springframework.boot.env.PropertySourceLoader=\ org.springframework.boot.env.PropertiesPropertySourceLoader,\ org.springframework.boot.env.YamlPropertySourceLoader
以上是准备环境变量步骤的核心部分剖析。
3.3、创建并初始化应用上下文
- 打印Banner
追踪printBanner方法,最终是通过创建SpringApplicationBannerPrinter对象进行打印的,以下是SpringApplicationBannerPrinter对象的关键代码
class SpringApplicationBannerPrinter {
...
// 创建banner打印器:fallbackBanner由SpringApplication对象传入
SpringApplicationBannerPrinter(ResourceLoader resourceLoader, Banner fallbackBanner) {
this.resourceLoader = resourceLoader;
this.fallbackBanner = fallbackBanner;
}
// 打印到日志
Banner print(Environment environment, Class<?> sourceClass, Log logger) {
Banner banner = getBanner(environment);
try {
logger.info(createStringFromBanner(banner, environment, sourceClass));
}
catch (UnsupportedEncodingException ex) {
logger.warn("Failed to create String for banner", ex);
}
return new PrintedBanner(banner, sourceClass);
}
// 打印到输出流 Banner print(Environment environment, Class<?> sourceClass, PrintStream out) { Banner banner = getBanner(environment); banner.printBanner(environment, sourceClass, out); return new PrintedBanner(banner, sourceClass); }
// 获取Banner
private Banner getBanner(Environment environment) {
Banners banners = new Banners();
// 获取图片和文本banner banners.addIfNotNull(getImageBanner(environment)); banners.addIfNotNull(getTextBanner(environment)); if (banners.hasAtLeastOneBanner()) { return banners; } // 创建SpringApplication时创建或指定的banner对象 if (this.fallbackBanner != null) { return this.fallbackBanner; } // 缺省 return DEFAULT_BANNER;
}
...
}
如果没有关闭打印选项,SpringBoot会使用系统输出流或日志打印应用的Banner。SpringBoot支持文本、图片和自定义Banner对象。
首先,SpringBoot默认会尝试从resouces目录下获取banner.txt或以banner.(gif,jpg,png)后缀的banner文件,可以通过spring.banner.location参数或spring.banner.image.location参数指定路径。其次,可以在创建SpringApplication对象后执行run方法前创建自定义的Banner对象。如果都没有设置,则SpringBoot将提供缺省的banner。
另外,可以通过spring.banner.charset参数指定打印到日志文件的banner内容编码。如果是桌面应用(Swing、AWT),SpringBoot会自动设置java.awt.headless为true,然后再打印输出。
- 创建应用上下文
应用上下文对象是Spring应用中角色很重的一个对象,SpringBoot的创建应用上下文的方式异常简单,直接根据web应用类型,使用反射技术,通过应用上下文的默认构造方法创建应用上下文对象实例。
protected ConfigurableApplicationContext createApplicationContext() { Class<?> contextClass = this.applicationContextClass; if (contextClass == null) { try { // 根据web应用类型创建对应的应用上下文获取上下文类型 switch (this.webApplicationType) { case SERVLET: // 本实例中为AnnotationConfigServletWebServerApplicationContext contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS); break; case REACTIVE: contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS); break; default: contextClass = Class.forName(DEFAULT_CONTEXT_CLASS); } } catch (ClassNotFoundException ex) { throw new IllegalStateException( "Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex); } } // 使用BeanUtils创建上下文对象实例 return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass); }
最终调用AnnotationConfigServletWebServerApplicationContext的无参构造方法,方法内部主要初始化了一个注解bean定义解析器和类路径bean定义扫描器。
public AnnotationConfigServletWebServerApplicationContext() { this.reader = new AnnotatedBeanDefinitionReader(this); this.scanner = new ClassPathBeanDefinitionScanner(this); }
当中,AnnotatedBeanDefinitionReader的初始化注意到调用了AnnotationConfigUtils类的registerAnnotationConfigProcessors方法,该方法注册了用于解析各种注解的处理器bean定义,这些处理器基本上属于BeanFactoryPostProcessor或BeanPostProcessor的实现类,在上下文刷新的refresh方法中(invokeBeanFactoryPostProcessors或registerBeanPostProcessors)将被调用,然后开始扫描解析各种注解。
public abstract class AnnotationConfigUtils { // 定义@Configuration注解处理器的bean名称,用于解析处理@Configuration及其派生注解 public static final String CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME = "org.springframework.context.annotation.internalConfigurationAnnotationProcessor"; ... // 定义@Autowired和@Value以及@Inject等相关注解处理器的bean名称 public static final String AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME = "org.springframework.context.annotation.internalAutowiredAnnotationProcessor"; ... // 定义JSR-250规范相关的注解处理器的bean名称,比如@PostConstruct、@PreDestroy等 public static final String COMMON_ANNOTATION_PROCESSOR_BEAN_NAME = "org.springframework.context.annotation.internalCommonAnnotationProcessor"; ... // 定义@EventListener注解的处理器的bean名称 public static final String EVENT_LISTENER_PROCESSOR_BEAN_NAME = "org.springframework.context.event.internalEventListenerProcessor"; ... public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) { registerAnnotationConfigProcessors(registry, null); } // 注册注解配置处理器:用于解析处理注解 public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors( BeanDefinitionRegistry registry, @Nullable Object source) { ... // bean定义集合:存放用于解析各种注解的处理器bean定义 Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8); // 注册解析@Configuration注解及其派生注解的处理器ConfigurationClassPostProcessor, // 它实现了BeanFactoryPostProcessor,在refresh方法中 if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) { // bean定义:实际的处理类为ConfigurationClassPostProcessor RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class); // 添加配置源:目前为null def.setSource(source); // 注册后添加到集合中 beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)); } // 注册解析@Autowired等注解的处理器AutowiredAnnotationBeanPostProcessor if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class); def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)); } // 注册解析@PostConstruct等注解的处理器CommonAnnotationBeanPostProcessor if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class); def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)); } ... // 注册解析@EventListener注解的处理器EventListenerMethodProcessor if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class); def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME)); } ... return beanDefs; } ... }
- 加载并创建异常报告器
异常报告器从通过加载解析META-INF/spring.factories文件中生命的SpringBootExceptionReporter创建。异常报告器目前配置在spring-boot模块下,只有一个实例。在SpringAppication运行过程中出现错误时,用来分析处理错误信息。
# Error Reporters org.springframework.boot.SpringBootExceptionReporter=\ org.springframework.boot.diagnostics.FailureAnalyzers
3.4、准备应用上下文
- 准备应用上下文
准备应用上下文其最核心的工作就是将配置源(Java配置类)注册为bean定义到容器中;如果是xml,则解析xml文件中的bean定义;如果是类路径(包),则扫面包下的所有类,符合条件的都注册为bean定义。
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) { // 为上下文设置环境变量 context.setEnvironment(environment); // 将beanNameGenerator等注册到容器中(单例) // 为上下文设置资源加载器resourceLoader以及为容器设置转换服务,如果存在的话 postProcessApplicationContext(context); // 应用初始化器:其中的一个SharedMetadataReaderFactoryContextInitializer被调用 // 为上下文添加了一个CachingMetadataReaderFactoryPostProcessor,在refresh时被调用 applyInitializers(context); // 触发上下文准备事件 listeners.contextPrepared(context); if (this.logStartupInfo) { logStartupInfo(context.getParent() == null); logStartupProfileInfo(context); } // 将命令行参数对象、banner对象注册到容器中等 ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); beanFactory.registerSingleton("springApplicationArguments", applicationArguments); if (printedBanner != null) { beanFactory.registerSingleton("springBootBanner", printedBanner); } if (beanFactory instanceof DefaultListableBeanFactory) { ((DefaultListableBeanFactory) beanFactory) .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding); } if (this.lazyInitialization) { context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor()); } // 合并配置源 // sources中的元素被注册为bean定义,当前只有WebMVCBootstrap,将被注册为bean定义 // getAllSources会将构建SpringApplication时指定的primarySources以及 // 创建SpringApplication对象后通过add或set方法配置添加的sources进行合并 Set<Object> sources = getAllSources(); Assert.notEmpty(sources, "Sources must not be empty"); // 加载配置源 load(context, sources.toArray(new Object[0])); // 触发上下文加载完成事件:准备就绪 listeners.contextLoaded(context); }
这里比较重要的是加载配置源信息部分。SpringBoot此时将配置源注册为bean定义,为接下来的注解解析做准备。sources是构建SpringApplication时指定的primarySources以及SpringApplication对象创建后自行添加的sources合并后的列表。当前指定了一个配置源就是引导类WebMVCBootstrap,如果注解了@SpringBootApplication、@Enablexxx或如@Configuration等,在上下文刷新方法refresh中(invokeBeanFactoryPostProcessors或registerBeanPostProcessors)将被注解处理器解析,解析为bean定义将被注册。
protected void load(ApplicationContext context, Object[] sources) { if (logger.isDebugEnabled()) { logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources)); } // 创建Bean定义加载器 BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources); if (this.beanNameGenerator != null) { loader.setBeanNameGenerator(this.beanNameGenerator); } if (this.resourceLoader != null) { loader.setResourceLoader(this.resourceLoader); } if (this.environment != null) { loader.setEnvironment(this.environment); } // 加载并注册指定配置源为bean定义:引导类WebMVCBootstrap被注册为bean定义 loader.load(); }
bean定义加载器针对不同的配置源初始化了三种bean定义的解析器,包括使用注解的Java配置类、xml文件以及类路径扫描三种方式的解析器。bean定义加载器loader创建之后,调用其load方法开始解析配置源,然后将解析到的符合条件的bean定义注册到容器中。
class BeanDefinitionLoader { ... BeanDefinitionLoader(BeanDefinitionRegistry registry, Object... sources) { Assert.notNull(registry, "Registry must not be null"); Assert.notEmpty(sources, "Sources must not be empty"); // 保存配置源 this.sources = sources; // 注解bean定义源(使用注解的Java配置类)解析器 this.annotatedReader = new AnnotatedBeanDefinitionReader(registry); // xml配置bean定义源(使用xml配置文件)解析器 this.xmlReader = new XmlBeanDefinitionReader(registry); if (isGroovyPresent()) { this.groovyReader = new GroovyBeanDefinitionReader(registry); } //类路径bean定义源(类路径下使用了注解的组件类)扫描器 this.scanner = new ClassPathBeanDefinitionScanner(registry); this.scanner.addExcludeFilter(new ClassExcludeFilter(sources)); } // 遍历配置源 int load() { int count = 0; for (Object source : this.sources) { count += load(source); } return count; } // 加载配置源 private int load(Object source) { Assert.notNull(source, "Source must not be null"); // 加载Java配置类源 if (source instanceof Class<?>) { return load((Class<?>) source); } ... } // 加载Java类配置源(注解方式) private int load(Class<?> source) { ... if (isEligible(source)) { // 使用注解解析器,将配置源注册为bean定义到容器中 this.annotatedReader.register(source); return 1; } return 0; } ... }
最后,注解解析器AnnotatedBeanDefinitionReader通过doRegisterBean方法将Java类配置源注册为bean定义。注意此时只是将Java类配置源注册为bean定义到容器中,但还未开始进行自动装配或注解解析等逻辑。如果是xml或package包资源,则将会进行xml文件的解析和路径扫描,测试将会将解析和扫描到的bean定义注册到容器中。
public class AnnotatedBeanDefinitionReader { ... // 将Java类配置源注册为bean定义,此时除了beanClass,其它参数都为null // beanClass当前为WebMVCBootstrap.class private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name, @Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier, @Nullable BeanDefinitionCustomizer[] customizers) { // 将beanClass封装为注解类型的bean定义对象 AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass); // 检查是否有条件注解,如果有,是否符合条件,如果不符合,将跳过 if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) { return; } // 设置实例化函数、作用域(默认单例为singleton)、beanName abd.setInstanceSupplier(supplier); ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd); abd.setScope(scopeMetadata.getScopeName()); String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry)); // 解析处理bean定义中通用的属性注解:如Lazy、Primary、DependsOn、Role、Description等 AnnotationConfigUtils.processCommonDefinitionAnnotations(abd); if (qualifiers != null) { for (Class<? extends Annotation> qualifier : qualifiers) { if (Primary.class == qualifier) { abd.setPrimary(true); } else if (Lazy.class == qualifier) { abd.setLazyInit(true); } else { abd.addQualifier(new AutowireCandidateQualifier(qualifier)); } } } if (customizers != null) { for (BeanDefinitionCustomizer customizer : customizers) { customizer.customize(abd); } } // 封装为bean定义持有对象 BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName); definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); // 最后WebMVCBootstrap注册到容器中 BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry); } ... }
注册完配置源后,调用listeners.contextLoaded触发上下文准备完成事件,上下文的准备到此就结束了。
3.5、应用启动
应用启动步骤包括刷新应用上下文、调用afterRefresh空方法和打印日志、发布ApplicationStartedEvent事件以及AvailabilityChangeEvent事件三部分。核心是刷新应用上下文,它也是Spring最核心的部分。
- 刷新应用上下文
SpringApplication#refreshContext方法最后调用了应用上下文的抽象父类AbstractApplicationContext#refresh方法执行应用上下文的刷新。
private void refreshContext(ConfigurableApplicationContext context) { refresh((ApplicationContext) context); if (this.registerShutdownHook) { try { context.registerShutdownHook(); } catch (AccessControlException ex) { // Not allowed in some environments. } } }
最后将调用AbstractApplicationContext的refresh方法
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext { ... // 刷新应用上下文 @Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { ... try { ... // 调用BeanFactoryPostProcessor // 自动装配注解等所有注解的解析(bean定义等)在这里完成 invokeBeanFactoryPostProcessors(beanFactory); ... // 初始化其它子类 // AnnotationConfigServletWebServerApplicationContext的父类覆盖了此方法, // 内置的Web服务器在这一步骤中启动 onRefresh(); ... // 初始化单例 finishBeanFactoryInitialization(beanFactory); ... } catch (BeansException ex) { ... } ... } } ... }
对于使用Java配置类注解方式的SpringBoot应用,invokeBeanFactoryPostProcessors方法的调用非常重要,自动装配注解以及其它组件的注解都在这里完成。此时在应用上下文的容器中已经注册的BeanFactoryPostProcessor中有一个ConfigurationClassPostProcessor处理器(在创建应用上下文AnnotationConfigServletWebServerApplicationContext对象时注册的,准确的说时其构造方法内部创建注解Bean定义解析器AnnotatedBeanDefinitionReader时创建的),它用于解析配置源即配置类(Configuration Class)。在这个步骤中,ConfigurationClassPostProcessor处理器将被调用,然后开始自动配置等相关配置类或注解的解析。
// 初始化和调用所有已经注册的BeanFactoryPostProcessor处理器bean protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) { // 统一在PostProcessorRegistrationDelegate中处理 PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors()); ... }
跟踪PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors方法
final class PostProcessorRegistrationDelegate { ... // 调用BeanFactoryPostProcessors public static void invokeBeanFactoryPostProcessors( ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) { ... if (beanFactory instanceof BeanDefinitionRegistry) { BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory; ... // 当前处理器实例列表 List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>(); // 从beanFactory中获取处理器 // 目前只有ConfigurationClassPostProcessor一个处理器 String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false); for (String ppName : postProcessorNames) { if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) { // 初始化bean放入当前列表 currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)); ... } } ... // 调用invokeBeanDefinitionRegistryPostProcessors方法处理 invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry); ... } ... // 调用invokeBeanDefinitionRegistryPostProcessors private static void invokeBeanDefinitionRegistryPostProcessors( Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) { // 遍历列表中的处理器 for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) { // 调用postProcessor的postProcessBeanDefinitionRegistry方法 postProcessor.postProcessBeanDefinitionRegistry(registry); } } ... }
接着,跟踪ConfigurationClassPostProcessor处理器的postProcessBeanDefinitionRegistry方法
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor, PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware { ... // BeanDefinitionRegistryPostProcessor接口实现方法 @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) { ... // 处理配置类bean定义 processConfigBeanDefinitions(registry); } ... // 处理配置类(@Configuration及其派生注解)bean定义 public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) { // 候选配置类bean定义列表 List<BeanDefinitionHolder> configCandidates = new ArrayList<>(); // 从容器中获取bean定义名称信息:包括了主配置源的Java配置类,目前是WebMVCBootstrap String[] candidateNames = registry.getBeanDefinitionNames(); // 遍历bean定义名称,获取bean定义,然后找到符合条件的候选bean定义即配置类bean for (String beanName : candidateNames) { // 从容器中根据bean的名字加载bean定义 BeanDefinition beanDef = registry.getBeanDefinition(beanName); // 过滤已经处理过的配置类bean,只是简单打印日志,不做处理 if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) { if (logger.isDebugEnabled()) { logger.debug("Bean definition has already been processed as a configuration class: " + beanDef); } } // 符合条件的配置类定义 else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) { // 加入到候选列表中,接下来将会解析器或扫描器逐个处理 configCandidates.add(new BeanDefinitionHolder(beanDef, beanName)); } // 剩余的丢弃 } // 如果没有@Configuration的配置类,直接返回 // Return immediately if no @Configuration classes were found if (configCandidates.isEmpty()) { return; } ... // 创建配置类解析器parser // Parse each @Configuration class ConfigurationClassParser parser = new ConfigurationClassParser( this.metadataReaderFactory, this.problemReporter, this.environment, this.resourceLoader, this.componentScanBeanNameGenerator, registry); // 候选配置类列表转换为集合set Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates); // 已解析的配置类集合 Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size()); // 循环遍历解析配置类 do { // 解析并运行注解的逻辑:很多自动配置相关的配置类将被扫描并保存在解析器parser中 parser.parse(candidates); parser.validate(); // 解析过程中发现的配置类集合 Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses()); // 先移除已经处理过的,如有的话 configClasses.removeAll(alreadyParsed); ... // 解析加载到的配置类:比如很多的自动配置类 this.reader.loadBeanDefinitions(configClasses); alreadyParsed.addAll(configClasses); candidates.clear(); if (registry.getBeanDefinitionCount() > candidateNames.length) { // 检擦是否还有新的配置类未处理,如果有,加入candidates中继续解析 } } while (!candidates.isEmpty()); ... } ... }
ConfigurationClassPostProcessor处理器内部使用ConfigurationClassParser解析器以及ConfigurationClassBeanDefinitionReader解析器遍历解析配置类的注解,然后注册符合条件的bean定义。
bean定义处理完成后,接着onRefresh将启动内嵌的Web服务器,这部分可参考第7节。
最后在finishBeanFactoryInitialization方法中初始化单例,其中涉及了bean的生命周期。
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) { ... // 初始化所有非延迟加载的单例 beanFactory.preInstantiateSingletons(); }
beanFactory为DefaultListableBeanFactory实例,跟踪其preInstantiateSingletons方法源码
@Override public void preInstantiateSingletons() throws BeansException { ... // bean名称列表 List<String> beanNames = new ArrayList<>(this.beanDefinitionNames); // 遍历然后初始化 for (String beanName : beanNames) { RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); // 非抽象、单例、非延迟加载的bean if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { // 工厂bean的初始化 if (isFactoryBean(beanName)) { // 初始化工厂bean本身 Object bean = getBean(FACTORY_BEAN_PREFIX + beanName); // 如果确实是FactoryBean类型实例 if (bean instanceof FactoryBean) { FactoryBean<?> factory = (FactoryBean<?>) bean; // 是否需要立即创建对应的bean boolean isEagerInit; ... if (isEagerInit) { // 如果确实需要立即初始化,则初始化 getBean(beanName); } } } // 普通bean的初始化 else { getBean(beanName); } } } // 对于智能初始化单例:触发调用其afterSingletonsInstantiated方法 for (String beanName : beanNames) { Object singletonInstance = getSingleton(beanName); if (singletonInstance instanceof SmartInitializingSingleton) { SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance; ... // 调用智能初始化bean的afterSingletonsInstantiated方法 smartSingleton.afterSingletonsInstantiated(); ... } } }
容器的getBean方法有多个重载方法,最终调用的是AbstractBeanFactory的doGetBean方法,其源码如下
protected <T> T doGetBean( String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException { // 格式化bean的名称:获取正确名称 String beanName = transformedBeanName(name); Object bean; // 先尝试从缓存中获取单例:三级缓存 Object sharedInstance = getSingleton(beanName); // 1.如果存在且无args参数 if (sharedInstance != null && args == null) { ... // 对FactoryBean的处理 bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); } // 缓存不存在或args不为null的情况 else { // 不允许重复初始化正在创建的bean if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } // 当前容器如果不存在,则尝试从父容器中创建 BeanFactory parentBeanFactory = getParentBeanFactory(); if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { // 最终也是父容器的doGetBean,即当前doGetBean方法 ... } ... try { // 当前要初始化的bean定义 RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); checkMergedBeanDefinition(mbd, beanName, args); // 保证当前初始化的bean,其依赖的bean先初始化 String[] dependsOn = mbd.getDependsOn(); if (dependsOn != null) { // 如果存在依赖 for (String dep : dependsOn) { // 将依赖的bean信息记录下来 registerDependentBean(dep, beanName); try { // 然后初始化依赖的bean getBean(dep); } catch (NoSuchBeanDefinitionException ex) { ... } } } // 创建单例bean if (mbd.isSingleton()) { // 使用单例工厂创建单例bean,并放入到容器(缓存),单例工厂使用了一个lambda表达式, // 其相当于一个匿名类,getSingleton方法中调用getObject()获取创建的单例对象 /* new ObjectFactory<Object>(){ @Override public Object getObject() throws BeansException { try { return createBean(beanName, mbd, args); } catch (BeansException ex) { ... } } } */ sharedInstance = getSingleton(beanName, () -> { try { // 创建bean return createBean(beanName, mbd, args); } catch (BeansException ex) { ... } }); // 对FactoryBean的处理 bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); } // 创建多例 else if (mbd.isPrototype()) { Object prototypeInstance = null; try { beforePrototypeCreation(beanName); // 创建bean prototypeInstance = createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } // 对FactoryBean的处理 bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); } // 其它生命周期如request、session、application的bean对象创建 else { String scopeName = mbd.getScope(); ... Scope scope = this.scopes.get(scopeName); ... try { Object scopedInstance = scope.get(beanName, () -> { beforePrototypeCreation(beanName); try { // 创建bean return createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } }); bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd); } catch (IllegalStateException ex) { ... } } } catch (BeansException ex) { ... } } // 类型检查 ... return (T) bean; }
所有的类,最终还是通过AbstractAutowireCapableBeanFactory的createBean方法创建
@Override protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException { // bean定义 RootBeanDefinition mbdToUse = mbd; ... try { // 如果容器中有InstantiationAwareBeanPostProcessor处理器 // 交给处理器创建bean对象实例 Object bean = resolveBeforeInstantiation(beanName, mbdToUse); if (bean != null) { return bean; } } catch (Throwable ex) { ... } try { // 调用doCreateBean方法创建 Object beanInstance = doCreateBean(beanName, mbdToUse, args); ... return beanInstance; } catch (BeanCreationException | ImplicitlyAppearedSingletonException ex | Throwable) { ... } } ... // 调用doCreateBean方法创建 protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException { // 尝试从工厂缓存获取包装的实例bean BeanWrapper instanceWrapper = null; if (mbd.isSingleton()) { instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); } // 如果没有 if (instanceWrapper == null) { // 调用createBeanInstance方法创建bean的包装类实例 instanceWrapper = createBeanInstance(beanName, mbd, args); } // 包装类中的原始bean实例和类型 Object bean = instanceWrapper.getWrappedInstance(); Class<?> beanType = instanceWrapper.getWrappedClass(); if (beanType != NullBean.class) { mbd.resolvedTargetType = beanType; } // MergedBeanDefinitionPostProcessor处理器可以在bean创建后修改bean定义信息, // 以改变接下来对bean进行属性填充或初始化过程中的行为,比如修改初始化方法等 // 如果定义了容器中有MergedBeanDefinitionPostProcessor处理器 // 将的bean此时可以对bean定义进行修改 synchronized (mbd.postProcessingLock) { if (!mbd.postProcessed) { try { applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); } catch (Throwable ex) { ... } mbd.postProcessed = true; } } // 提前缓存为填充属性和初始化的bean对象,以有效解决可能的循环引用问题 boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); // 如果是单例、允许互相引用其单例正在创建中 if (earlySingletonExposure) { ... // 提前缓存 addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); } // 准备初始化bean:属性填充即依赖注入和初始化 Object exposedObject = bean; try { // 填充属性:依赖注入 populateBean(beanName, mbd, instanceWrapper); // 初始化bean exposedObject = initializeBean(beanName, exposedObject, mbd); } catch (Throwable ex) { ... } // 循环引用的一些处理 if (earlySingletonExposure) { ... } // 注册bean的关闭事件 // 如果bean实现了DisposableBean或DestructionAwareBeanPostProcessor接口 // bean销毁时,将调用destroy方法 // 如果bean配置了destroy-method属性,同时也会调用destroy-method属性指定的方法 try { registerDisposableBeanIfNecessary(beanName, bean, mbd); } catch (BeanDefinitionValidationException ex) { ... } return exposedObject; } ... // 调用createBeanInstance方法创建bean的包装类实例 protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) { // 确保bean的类型已经处理 Class<?> beanClass = resolveBeanClass(mbd, beanName); ... // 如果有实例化提供者,则调用其创建bean实例 Supplier<?> instanceSupplier = mbd.getInstanceSupplier(); if (instanceSupplier != null) { return obtainFromSupplier(instanceSupplier, beanName); } // 如果该bean定义了工厂方法,则调用其工厂方法创建bean实例再 if (mbd.getFactoryMethodName() != null) { return instantiateUsingFactoryMethod(beanName, mbd, args); } ... // 自动装配的构造参数的构造方法创建 Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName); if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR || mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) { return autowireConstructor(beanName, mbd, ctors, args); } // 默认的无参构造方法创建 ctors = mbd.getPreferredConstructors(); if (ctors != null) { return autowireConstructor(beanName, mbd, ctors, null); } // 调用无参构造方法创建bean return instantiateBean(beanName, mbd); } ... // 初始化bean protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) { // 如果该bean实现了BeanNameAware、BeanClassLoaderAware、BeanFactoryAware接口, // 将调用其实现的set方法 ... invokeAwareMethods(beanName, bean); ... // 如果该bean实现了BeanPostProcessor接口, // 由于ApplicationContextAwareProcessor处理器代理了 // 在初始化前调用postProcessBeforeInitialization方法 Object wrappedBean = bean; if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } // 调用初始化方法 try { // 如果该bean实现了InitializingBean接口,则调用其afterPropertiesSet方法 // 如果该bean配置了init-method属性,则调用init-method属性指定的方法 invokeInitMethods(beanName, wrappedBean, mbd); } catch (Throwable ex) { ... } // 如果该bean实现了BeanPostProcessor接口, // 在初始化后调用postProcessAfterInitialization方法 if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } return wrappedBean; }
刷新上下文的主要工作到此就完成,自动装配、配置类等注解已经被解析处理,所有的单例已经被实例化(除了延迟加载),而Web容器也在此步骤中启动了。
- afterRefresh空方法
应用启动步骤中,调用了一个留给子类实现或做为后续扩展的afterRefresh空方法。afterRefresh空方法之后,接着打印了启动日志。
- 发布ApplicationStartedEvent事件以及AvailabilityChangeEvent事件。
应用启动工作完成,SpringBoot发布ApplicationStartedEvent事件以及AvailabilityChangeEvent事件。AvailabilityChangeEvent可用性变更事件包括两类,一类用于标识应用当前的生存状态,应用如正常启动时生存状态被标识为正确运行LivenessState.CORRECT;另外一类标识应用当前服务状态,如果应用准备就绪时服务状态被标识为等待接受请求状态ReadinessState.ACCEPTING_TRAFFIC。
3.6、应用就绪
在应用就绪步骤中,SpringBoot做了两件事,一个是运行注册在上下文中的所有ApplicationRunner和CommandLineRunner对象定义的任务;第二个就是发布ApplicationReadyEvent应用就绪事件以及AvailabilityChangeEvent可用性变更事件,将应用标识为等待接受请求的状态ReadinessState.ACCEPTING_TRAFFIC。两件事情做完之后,SpringBoot应用便开始对外提供服务。
下面是运行ApplicationRunner和CommandLineRunner任务的源码剖析
// 传递应用上下文以及命令行参数 private void callRunners(ApplicationContext context, ApplicationArguments args) { // 任务运行者列表 List<Object> runners = new ArrayList<>(); // 从容器中获取ApplicationRunner和CommandLineRunner实例 runners.addAll(context.getBeansOfType(ApplicationRunner.class).values()); runners.addAll(context.getBeansOfType(CommandLineRunner.class).values()); AnnotationAwareOrderComparator.sort(runners); // 排序后遍历调用 for (Object runner : new LinkedHashSet<>(runners)) { if (runner instanceof ApplicationRunner) { // 调用ApplicationRunner callRunner((ApplicationRunner) runner, args); } if (runner instanceof CommandLineRunner) { // 调用CommandLineRunner callRunner((CommandLineRunner) runner, args); } } } // 调用ApplicationRunner private void callRunner(ApplicationRunner runner, ApplicationArguments args) { try { (runner).run(args); } catch (Exception ex) { throw new IllegalStateException("Failed to execute ApplicationRunner", ex); } } // 调用CommandLineRunner private void callRunner(CommandLineRunner runner, ApplicationArguments args) { try { (runner).run(args.getSourceArgs()); } catch (Exception ex) { throw new IllegalStateException("Failed to execute CommandLineRunner", ex); } }
plicationRunner和CommandLineRunner属于1.x时代的接口,从执行时间点看,比监听ApplicationReadyEvent应用就绪事件的监听器早一点执行,但只能获取应用的命令行参数,具体的使用场景有待探索。
原文链接:https://blog.csdn.net/chengshangqian/article/details/117390997
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)