Spring Boot 启动流程分析

想来用了这么久的 Spring Boot,但一直没仔细了解它是怎么启动的。那既然想起来了,不如趁热打铁,从它的入口开始,深入看看 Spring Boot 在启动时都做了些什么。

启动入口

入口这部分就没啥说的,跟个 Hello world 差不多,一个 main 方法执行 SpringApplication#run 来启动整个 Spring Boot 应用。

1
2
3
4
5
6
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}

@SpringBootApplication 注解

进到 @SpringBootApplication 注解的源码可以看出,它实际上是 @SpringBootConfiguration@EnableAutoConfiguration@ComponentScan 的组合。

1
2
3
4
5
6
7
8
9
10
11
12
13
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class)
})
public @interface SpringBootApplication {
// 略
}

@SpringBootConfiguration 注解

@SpringBootConfiguration 注解实际上只是 @Configuration 注解的套娃,区别只有两点:

  1. @SpringBootConfiguration 是 Spring Boot 提供的注解,而 @Configuration 是 Spring 提供的注解;
  2. @SpringBootConfiguration 注解在整个应用中只能出现一次,@Configuration 注解则可以需要有多少就用多少次。
1
2
3
4
5
6
7
8
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Indexed
public @interface SpringBootConfiguration {
// 略
}

@EnableAutoConfiguration 注解

@EnableAutoConfiguration 注解通过引入 AutoConfigurationImportSelector 来开启 Spring Boot 的自动配置功能。这部分内容我在另一篇博文 Spring Boot 自动配置的原理中有详细的说明,这里就不再重复了。

@ComponentScan 注解

@ComponentScan 注解用来配置 Spring 如何扫描组件。我们可以通过设定 basePackageClassesbasePackages 属性来指定从哪些包中扫描,而在不指定的情况下,Spring 就会从带有这个注解的类所在的包开始扫描。

因为这个注解会在启动类中被引入,而启动类又在项目最顶层的包中(应该没有谁闲的会去挪启动类的位置吧),所以 Spring 就会从顶层包开始往下扫描组件。

SpringApplication 类

从启动类对 SpringApplication#run 的调用一路追下去,最后会走到 SpringApplication 类的这个代码块:

1
2
3
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return new SpringApplication(primarySources).run(args);
}

SpringApplication 的构造方法

可以看到这里先实例化了一个 SpringApplication 对象,那么顺着对应的构造方法一路追下去,最后会看到这样一个构造方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 判断应用程序的类型
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 实例化bootstrap registry initializer
this.bootstrapRegistryInitializers = new ArrayList<>(
getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
// 实例化所有可用的initializer
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 实例化所有可用的listener
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 找到主类
this.mainApplicationClass = deduceMainApplicationClass();
}

判断应用程序的类型

Spring Boot 需要判断应用是哪种类型,来决定要不要启动它内嵌的 web server,以及启动哪种 web server。它会根据这样一个规则来判断当前应用的类型:

  • 如果能找到 org.springframework.web.reactive.DispatcherHandler 类,同时找不到 org.springframework.web.servlet.DispatcherServletorg.glassfish.jersey.servlet.ServletContainer,那么就判定当前应用是一个 reactive web 应用,并会在将来启动面向 reactive 的 web server;
  • 如果 org.springframework.web.servlet.DispatcherServletorg.glassfish.jersey.servlet.ServletContainer 都找不到,说明这个应用不是一个 web application,将来也不会启动任何 web server;
  • 如果以上条件都不符合,那么就判定这个应用是一个 servlet web 应用,将来会启动面向 servlet 的 web server。

实例化 initializer 和 listener

点进 getSpringFactoriesInstances 方法的实现并顺着追下去,最终可以看到这样一个代码块:

1
2
3
private <T> List<T> getSpringFactoriesInstances(Class<T> type, ArgumentResolver argumentResolver) {
return SpringFactoriesLoader.forDefaultResourceLocation(getClassLoader()).load(type, argumentResolver);
}

再顺着 forDefaultResourceLocation 方法的实现,最终会走到这里:

1
2
3
4
5
6
7
8
9
public static SpringFactoriesLoader forResourceLocation(String resourceLocation, @Nullable ClassLoader classLoader) {
Assert.hasText(resourceLocation, "'resourceLocation' must not be empty");
ClassLoader resourceClassLoader = (classLoader != null ? classLoader :
SpringFactoriesLoader.class.getClassLoader());
Map<String, SpringFactoriesLoader> loaders = cache.computeIfAbsent(
resourceClassLoader, key -> new ConcurrentReferenceHashMap<>());
return loaders.computeIfAbsent(resourceLocation, key ->
new SpringFactoriesLoader(classLoader, loadFactoriesResource(resourceClassLoader, resourceLocation)));
}

看起来好像云里雾里的,下断点调试一下看出来了,这里就是扫描所有 META-INF 目录下的 spring.factories 文件,并把里面所有的键值对放到一个 Map 里。最后我们可以得到一个包含了这个 Map 的 SpringFactoriesLoader 对象。

接着看 load 方法,顺着追下去会走到这个代码块:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public <T> List<T> load(Class<T> factoryType, @Nullable ArgumentResolver argumentResolver,
@Nullable FailureHandler failureHandler) {

Assert.notNull(factoryType, "'factoryType' must not be null");
List<String> implementationNames = loadFactoryNames(factoryType);
logger.trace(LogMessage.format("Loaded [%s] names: %s", factoryType.getName(), implementationNames));
List<T> result = new ArrayList<>(implementationNames.size());
FailureHandler failureHandlerToUse = (failureHandler != null) ? failureHandler : THROWING_FAILURE_HANDLER;
for (String implementationName : implementationNames) {
T factory = instantiateFactory(implementationName, factoryType, argumentResolver, failureHandlerToUse);
if (factory != null) {
result.add(factory);
}
}
AnnotationAwareOrderComparator.sort(result);
return result;
}

这里就是从上面得到的 Map 中找到 factoryType 传进来的接口对应的实现类,分别调用它们的构造方法将其实例化,然后把得到的对象放在 List 里面返回。

实例化 listener 也是一样的流程。

找到主类

顺着 deduceMainApplicationClass 的实现,会注意到这么两个方法:

1
2
3
4
5
6
7
8
9
10
11
private Class<?> deduceMainApplicationClass() {
return StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE)
.walk(this::findMainClass)
.orElse(null);
}

private Optional<Class<?>> findMainClass(Stream<StackFrame> stack) {
return stack.filter((frame) -> Objects.equals(frame.getMethodName(), "main"))
.findFirst()
.map(StackWalker.StackFrame::getDeclaringClass);
}

看起来挺简单粗暴的,就是遍历栈帧,找执行了 main 方法的那个栈,然后找到这个栈对应的类。

run 方法

经过上面一顿操作,这个 SpringApplication 对象就初始化好了,接下来就会调用它的 run 方法开始启动。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
public ConfigurableApplicationContext run(String... args) {
Startup startup = Startup.create();
if (this.registerShutdownHook) {
SpringApplication.shutdownHook.enableShutdownHookAddition();
}
// 创建 bootstrap context
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
ConfigurableApplicationContext context = null;
// 进入无头模式
configureHeadlessProperty();
// 启动listener
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 准备环境
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
Banner printedBanner = printBanner(environment);
// 创建application context
context = createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
// 刷新application context
refreshContext(context);
afterRefresh(context, applicationArguments);
// 收尾
startup.started();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), startup);
}
listeners.started(context, startup.timeTakenToStarted());
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
// 略
}
try {
if (context.isRunning()) {
listeners.ready(context, startup.ready());
}
}
catch (Throwable ex) {
// 略
}
return context;
}

创建 bootstrap context

点进 createBootstrapContext 方法,可以看到这样一个代码块:

1
2
3
4
5
private DefaultBootstrapContext createBootstrapContext() {
DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();
this.bootstrapRegistryInitializers.forEach((initializer) -> initializer.initialize(bootstrapContext));
return bootstrapContext;
}

在构造 SpringApplication 时准备的 this.bootstrapRegistryInitializers 在这用上了。看代码的话就是分别执行每个 initializer 的 initailize 方法。但是我这个应用里面没有 BootstrapRegistryInitializer 的实现类,所以也就没法深入进去看它到底干了什么。

进入无头模式

在 Oracle 的文档 Using Headless Mode in the Java SE Platform中提到

Headless mode is a system configuration in which the display device, keyboard, or mouse is lacking. Sounds unexpected, but actually you can perform different operations in this mode, even with graphic data.

Where it is applicable? Let’s say that your application repeatedly generates a certain image, for example, a graphical authorization code that must be changed every time a user logs in to the system. When creating an image, your application needs neither the display nor the keyboard. Let’s assume now that you have a mainframe or dedicated server on your project that has no display device, keyboard, or mouse. The ideal decision is to use this environment’s substantial computing power for the visual as well as the nonvisual features. An image that was generated in the headless mode system then can be passed to the headful system for further rendering.

其实就是,像 web 服务之类不需要显示界面的应用,就可以让它进入无头模式,让它在没有显示器等输入输出设备时也能启动,还可以提高计算效率。

启动 listener

点进 getRunListeners 的实现可以看到如下代码块:

1
2
3
4
5
6
7
8
9
10
11
12
13
private SpringApplicationRunListeners getRunListeners(String[] args) {
ArgumentResolver argumentResolver = ArgumentResolver.of(SpringApplication.class, this);
argumentResolver = argumentResolver.and(String[].class, args);
List<SpringApplicationRunListener> listeners = getSpringFactoriesInstances(SpringApplicationRunListener.class,
argumentResolver);
SpringApplicationHook hook = applicationHook.get();
SpringApplicationRunListener hookListener = (hook != null) ? hook.getRunListener(this) : null;
if (hookListener != null) {
listeners = new ArrayList<>(listeners);
listeners.add(hookListener);
}
return new SpringApplicationRunListeners(logger, listeners, this.applicationStartup);
}

看到 getSpringFactoriesInstances 有没有感觉很熟悉?对,这一步就是尝试从 spring.factories 里尝试找到 SpringApplicationRunListener 的实现类。默认来说这里只能找到 EventPublishingRunListener,它是用来发布各种 SpringBootEvent 的。

除了从 spring.factories 尝试获取 listener 之外,Spring Boot 也会尝试从 SpringApplicationHook 中找到 hook 进来的 listener。看了下代码,似乎我们可以在入口的 main 方法里调用 SpringApplication#withHook 来添加我们需要的 hook,但是我的应用里面也没有什么能用的,所以也没法深挖了。

在得到这些 listener 之后,就会实例化一个 SpringApplicationRunListeners 对象并返回回去,然后在 SpringApplicationRunListeners#starting 方法中调用各个 listener 的 starting 方法。此时,上面得到的 EventPublishingRunListener 就会广播出去一条 ApplicationStartingEvent 事件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void starting(ConfigurableBootstrapContext bootstrapContext, Class<?> mainApplicationClass) {
doWithListeners("spring.boot.application.starting", (listener) -> listener.starting(bootstrapContext),
(step) -> {
if (mainApplicationClass != null) {
step.tag("mainApplicationClass", mainApplicationClass.getName());
}
});
}

private void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction,
Consumer<StartupStep> stepAction) {
StartupStep step = this.applicationStartup.start(stepName);
this.listeners.forEach(listenerAction);
if (stepAction != null) {
stepAction.accept(step);
}
step.end();
}

准备环境

Spring 中的 Environment 负责两件事:

  • 加载配置好的各种 property 的值
  • 后续通过各种方法获取 property 的值

在 Spring Boot 里,property 的值可以通过 YAML 文件或 properties 文件、环境变量,和命令行参数这三种方法配置。此外,Spring Boot 会依照一定的优先级来决定采用哪个 property 值,高优先级的会覆盖低优先级的。常见的几种配置方式会按照如下的优先级排列:

  1. 开发者工具 Devtools 全局配置
  2. 命令行指定的参数(如 --server.port=8080
  3. JNDI 参数
  4. Java 系统参数(通过 -D 指定的参数)
  5. 系统环境变量
  6. 对应不同环境的 application-{profile}.yml 配置文件
  7. application.yml 配置文件
  8. 默认参数

点进 prepareEvent 方法的实现,可以看到这个代码块(我稍微重新格式化了一下,看起来更舒服一点):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
private ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners,
DefaultBootstrapContext bootstrapContext,
ApplicationArguments applicationArguments
) {
// Create and configure the environment
// 获得应用的环境(servlet / reactive)
ConfigurableEnvironment environment = getOrCreateEnvironment();
configureEnvironment(environment, applicationArguments.getSourceArgs());
ConfigurationPropertySources.attach(environment);
listeners.environmentPrepared(bootstrapContext, environment);
DefaultPropertiesPropertySource.moveToEnd(environment);
Assert.state(!environment.containsProperty("spring.main.environment-prefix"),
"Environment prefix cannot be set via properties.");
bindToSpringApplication(environment);
if (!this.isCustomEnvironment) {
EnvironmentConverter environmentConverter = new EnvironmentConverter(getClassLoader());
environment = environmentConverter.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
}
ConfigurationPropertySources.attach(environment);
return environment;
}

private ConfigurableEnvironment getOrCreateEnvironment() {
if (this.environment != null) {
return this.environment;
}
ConfigurableEnvironment environment = this.applicationContextFactory.createEnvironment(this.webApplicationType);
if (environment == null && this.applicationContextFactory != ApplicationContextFactory.DEFAULT) {
environment = ApplicationContextFactory.DEFAULT.createEnvironment(this.webApplicationType);
}
return (environment != null) ? environment : new ApplicationEnvironment();
}

首先在 getOrCreateEnvironment 中,Spring Boot 会根据应用类型 (reactive、servlet 或 none) 来创建对应的环境。比如我这个是一个 servlet 应用,那么 createEnvironment 方法就会返回一个 ApplicationServletEnvironment 对象,并返回回去。

接下来到 configureEnvironment 里面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
if (this.addConversionService) {
environment.setConversionService(new ApplicationConversionService());
}
configurePropertySources(environment, args);
configureProfiles(environment, args);
}

protected void configurePropertySources(ConfigurableEnvironment environment, String[] args) {
MutablePropertySources sources = environment.getPropertySources();
// 如果有default properties,那就把它们加到MutablePropertySources里面
if (!CollectionUtils.isEmpty(this.defaultProperties)) {
DefaultPropertiesPropertySource.addOrMerge(this.defaultProperties, sources);
}
// addCommandLineProperties默认是true
// args就是启动时传进来的参数,--server.port=8080之类的
// 如果有指定参数,那就把这些参数包在SimpleCommandLinePropertySource里面,并添加到MutablePropertySources中
if (this.addCommandLineProperties && args.length > 0) {
String name = CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME;
if (sources.contains(name)) {
PropertySource<?> source = sources.get(name);
CompositePropertySource composite = new CompositePropertySource(name);
composite.addPropertySource(new SimpleCommandLinePropertySource("springApplicationCommandLineArgs", args));
composite.addPropertySource(source);
sources.replace(name, composite);
}
else {
sources.addFirst(new SimpleCommandLinePropertySource(args));
}
}
}

protected void configureProfiles(ConfigurableEnvironment environment, String[] args) {
}

这个 conversion service 是干啥用的暂时还没搞明白,先留个坑,专注于主线。爬了些文大概看明白了,ConversionService 是用来处理各种类型转换的,比如把字符串转换成 Long 或者日期等。

这里的话就是把各种参数(比如附加在启动命令里面的命令行参数)给填充到 environment 对象里。MutablePropertySources 就是存放 property 的载体,在前面调用 createEnvironment 的时候,ApplicationServletEnvironment 继承的 AbstractEnvironment 类的构造方法就会创建一个新的 MutablePropertySources 实例。

接下来 ConfigurationPropertySources#attach 方法里面,environment 的 propertySources 会被封装成一个 ConfigurationPropertySource 并添加到 environment 中。

环境准备完成后,Spring Boot 会发布一个 ApplicationEnvironmentPreparedEvent 事件。

然后 Spring Boot 会把这个 environment 对象与 SpringApplication 绑定起来。但是绑定这部分暂时也没看明白,依旧是专注于主线,以后有时间再说。

创建 application context

这里会根据应用的类型(reactive 或 servlet)来创建对应的 application context 对象。

1
2
3
protected ConfigurableApplicationContext createApplicationContext() {
return this.applicationContextFactory.create(this.webApplicationType);
}

debug 进去,走到了 DefaultApplicationContextFactory 的这两个方法中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@Override
public ConfigurableApplicationContext create(WebApplicationType webApplicationType) {
try {
return getFromSpringFactories(
webApplicationType,
ApplicationContextFactory::create,
this::createDefaultApplicationContext);
}
catch (Exception ex) {
throw new IllegalStateException("Unable create a default ApplicationContext instance, "
+ "you may need a custom ApplicationContextFactory", ex);
}
}

private <T> T getFromSpringFactories(
WebApplicationType webApplicationType,
BiFunction<ApplicationContextFactory, WebApplicationType, T> action,
Supplier<T> defaultResult
) {
for (ApplicationContextFactory candidate : SpringFactoriesLoader.loadFactories(ApplicationContextFactory.class,getClass().getClassLoader())) {
T result = action.apply(candidate, webApplicationType);
if (result != null) {
return result;
}
}
return (defaultResult != null) ? defaultResult.get() : null;
}

在这个循环里它会分别执行 ReactiveWebServerApplicationContextFactoryServletWebServerApplicationContextFactory 里面的 create 方法,而 create 方法里会判断当前应用的类型,来决定要不要创建对应的 application context。

1
2
3
4
5
6
7
8
9
10
11
@Override
public ConfigurableApplicationContext create(WebApplicationType webApplicationType) {
return (webApplicationType != WebApplicationType.SERVLET) ? null : createContext();
}

private ConfigurableApplicationContext createContext() {
if (!AotDetector.useGeneratedArtifacts()) {
return new AnnotationConfigServletWebServerApplicationContext();
}
return new ServletWebServerApplicationContext();
}

创建好 application context 实例后,Spring Boot 会开始准备 context 的内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
private void prepareContext(
DefaultBootstrapContext bootstrapContext,
ConfigurableApplicationContext context,
ConfigurableEnvironment environment,
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments,
Banner printedBanner
) {
// 绑定环境
context.setEnvironment(environment);
// 后置处理
postProcessApplicationContext(context);
addAotGeneratedInitializerIfNecessary(this.initializers);
// 执行各个initializer的initialize方法
applyInitializers(context);
// 发布事件
listeners.contextPrepared(context);
// 发布bootstrap context被关闭的事件
bootstrapContext.close(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// 注册启动相关的单例bean
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
// 设置是否允许循环引用,是否允许覆盖注册
if (beanFactory instanceof AbstractAutowireCapableBeanFactory autowireCapableBeanFactory) {
autowireCapableBeanFactory.setAllowCircularReferences(this.allowCircularReferences);
if (beanFactory instanceof DefaultListableBeanFactory listableBeanFactory) {
listableBeanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
}
// 处理延迟初始化
if (this.lazyInitialization) {
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
// 是否要保持JVM持续运行
// 为了应对Java 21引入的虚拟线程产生的问题
// 因为虚拟线程都是守护线程,而在只有守护线程运行时,JVM就会退出
// 所以这里会启动一个非守护线程来保持JVM能持续运行下去
if (this.keepAlive) {
context.addApplicationListener(new KeepAlive());
}
context.addBeanFactoryPostProcessor(new PropertySourceOrderingBeanFactoryPostProcessor(context));
// 不考虑AOT优化时,加载primarySources和sources
if (!AotDetector.useGeneratedArtifacts()) {
// Load the sources
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[0]));
}
listeners.contextLoaded(context);
}

注册启动相关的单例 bean

我对注册启动相关的单例 bean 很感兴趣,于是逐层点进 registerSingleton 的实现,看到了下列代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// DefaultListableBeanFactory
@Override
public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException {
super.registerSingleton(beanName, singletonObject);
updateManualSingletonNames(set -> set.add(beanName), set -> !this.beanDefinitionMap.containsKey(beanName));
clearByTypeCache();
}

// DefaultSingletonBeanRegistry
@Override
public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException {
Assert.notNull(beanName, "Bean name must not be null");
Assert.notNull(singletonObject, "Singleton object must not be null");
synchronized (this.singletonObjects) {
Object oldObject = this.singletonObjects.get(beanName);
if (oldObject != null) {
throw new IllegalStateException("Could not register object [" + singletonObject +
"] under bean name '" + beanName + "': there is already object [" + oldObject + "] bound");
}
addSingleton(beanName, singletonObject);
}
}

protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}

看下来就是,在注册一个单例 bean 的时候,会传进来 bean 的名字和实际的对象。在 registerSingleton 中首先检查这个名字是不是已经被注册过了,没有被注册过的话就会调用 addSingleton 来注册。而所谓注册,就是:

  • singletonObjects 这个 Map 里面增加一个条目,key 是 bean 的名字,value 是 bean 对应的对象;
  • singletonFactoriesearlySingletonObjects 中删掉以这个 bean 名字为 key 的条目;(不过这两个 Map 我也暂时没看懂是干什么的)
  • registeredSingletons 这个 Set 里面记录这次注册的 bean 的名字。

返回到 registerSingleton 之后,继续执行 updateManualSingletonNames 方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
private void updateManualSingletonNames(Consumer<Set<String>> action, Predicate<Set<String>> condition) {
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
synchronized (this.beanDefinitionMap) {
if (condition.test(this.manualSingletonNames)) {
Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
action.accept(updatedSingletons);
this.manualSingletonNames = updatedSingletons;
}
}
}
else {
// Still in startup registration phase
if (condition.test(this.manualSingletonNames)) {
action.accept(this.manualSingletonNames);
}
}
}

在应用启动的时候,方法会走到 else 这部分,也就是直接向 manualSingletonNames 这个 Set 添加这次注册的 bean 的名字。manualSingletonNames 这个 Set 存放的就是手动注册的各个 bean 的名字。

然后执行 clearByTypeCache 方法,把这两个 cache 清除。

1
2
3
4
private void clearByTypeCache() {
this.allBeanNamesByType.clear();
this.singletonBeanNamesByType.clear();
}

加载 primarySources 和 sources

getAllSources 会把 primarySourcessources 放进一个 Set 里面返回。

1
2
3
4
5
6
7
8
9
10
public Set<Object> getAllSources() {
Set<Object> allSources = new LinkedHashSet<>();
if (!CollectionUtils.isEmpty(this.primarySources)) {
allSources.addAll(this.primarySources);
}
if (!CollectionUtils.isEmpty(this.sources)) {
allSources.addAll(this.sources);
}
return Collections.unmodifiableSet(allSources);
}

然后走到 load 方法,把 bean 加载到 application context:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
protected void load(ApplicationContext context, Object[] sources) {
if (logger.isDebugEnabled()) {
logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
}
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);
}
loader.load();
}

private BeanDefinitionRegistry getBeanDefinitionRegistry(ApplicationContext context) {
if (context instanceof BeanDefinitionRegistry registry) {
return registry;
}
if (context instanceof AbstractApplicationContext abstractApplicationContext) {
return (BeanDefinitionRegistry) abstractApplicationContext.getBeanFactory();
}
throw new IllegalStateException("Could not locate BeanDefinitionRegistry");
}

protected BeanDefinitionLoader createBeanDefinitionLoader(BeanDefinitionRegistry registry, Object[] sources) {
return new BeanDefinitionLoader(registry, sources);
}

// 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;
this.annotatedReader = new AnnotatedBeanDefinitionReader(registry);
this.xmlReader = new XmlBeanDefinitionReader(registry);
this.groovyReader = (isGroovyPresent() ? new GroovyBeanDefinitionReader(registry) : null);
this.scanner = new ClassPathBeanDefinitionScanner(registry);
this.scanner.addExcludeFilter(new ClassExcludeFilter(sources));
}

首先这里会执行 getBeanDefinitionRegistry 方法。因为这个应用的 application context 是一个 AnnotationConfigServletWebServerApplicationContext,而它又层层继承于 BeanDefinitionRegistry,所以这里返回的就是当前的 application context。得到 bean defininition registry 之后,就会用它来初始化一个 BeanDefinitionLoader 对象。BeanDefinitionLoader 的构造方法里面会初始化各种 reader 和 scanner,来支持从不同的资源(XML、Java Config 等)加载 bean definition。

得到 BeanDefinitionLoader 后,Spring Boot 会把 bean 名字的生成器等自定义部件绑定上去。不过默认情况下它们都是 null。然后,就会执行 BeanDefinitionLoaderload 方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
void load() {
for (Object source : this.sources) {
load(source);
}
}

private void load(Object source) {
Assert.notNull(source, "Source must not be null");
if (source instanceof Class<?> clazz) {
load(clazz);
return;
}
if (source instanceof Resource resource) {
load(resource);
return;
}
if (source instanceof Package pack) {
load(pack);
return;
}
if (source instanceof CharSequence sequence) {
load(sequence);
return;
}
throw new IllegalArgumentException("Invalid source type " + source.getClass());
}

private void load(Class<?> source) {
if (isGroovyPresent() && GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
// Any GroovyLoaders added in beans{} DSL can contribute beans here
GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source, GroovyBeanDefinitionSource.class);
((GroovyBeanDefinitionReader) this.groovyReader).beans(loader.getBeans());
}
if (isEligible(source)) {
this.annotatedReader.register(source);
}
}

private boolean isEligible(Class<?> type) {
return !(type.isAnonymousClass() || isGroovyClosure(type) || hasNoConstructors(type));
}

虽然这里会遍历 sources,但是实际上 sources 里面只有应用的主启动类,所以最终会走到 load(Class<?> source) 方法中。因为应用中没有 Groovy,所以第一个判断会被跳过,然后经过 isEligible 中的三个判断之后,走进 register 方法,并最终进入 AnnotatedBeanDefinition#doRegisterBean 方法中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
public void register(Class<?>... componentClasses) {
for (Class<?> componentClass : componentClasses) {
registerBean(componentClass);
}
}

public void registerBean(Class<?> beanClass) {
doRegisterBean(beanClass, null, null, null, null);
}

private <T> void doRegisterBean(
Class<T> beanClass,
@Nullable String name,
@Nullable Class<? extends Annotation>[] qualifiers,
@Nullable Supplier<T> supplier,
@Nullable BeanDefinitionCustomizer[] customizers
) {

AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
}

abd.setAttribute(ConfigurationClassUtils.CANDIDATE_ATTRIBUTE, Boolean.TRUE);
abd.setInstanceSupplier(supplier);
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
// 设定这个bean的scope,singleton、prototype等
abd.setScope(scopeMetadata.getScopeName());
// 生成bean的名字
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));

// 根据类上的注解设定bean的属性,即处理@Lazy、@Primary等
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);
}
}

BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}

static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {
AnnotationAttributes lazy = attributesFor(metadata, Lazy.class);
if (lazy != null) {
abd.setLazyInit(lazy.getBoolean("value"));
}
else if (abd.getMetadata() != metadata) {
lazy = attributesFor(abd.getMetadata(), Lazy.class);
if (lazy != null) {
abd.setLazyInit(lazy.getBoolean("value"));
}
}

if (metadata.isAnnotated(Primary.class.getName())) {
abd.setPrimary(true);
}
AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class);
if (dependsOn != null) {
abd.setDependsOn(dependsOn.getStringArray("value"));
}

AnnotationAttributes role = attributesFor(metadata, Role.class);
if (role != null) {
abd.setRole(role.getNumber("value").intValue());
}
AnnotationAttributes description = attributesFor(metadata, Description.class);
if (description != null) {
abd.setDescription(description.getString("value"));
}
}

这里会处理传进来的类,为它创建一个 BeanDefinition 并设置各种属性,然后调用 BeanDefinitionReaderUtils#registerBeanDefinition 把这个 bean 注册到 application context 中。因为这一步传进来的只有主启动类,所以只会注册一个由主启动类生成的 bean。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder,
BeanDefinitionRegistry registry
) throws BeanDefinitionStoreException {

// Register bean definition under primary name.
String beanName = definitionHolder.getBeanName();
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

// Register aliases for bean name, if any.
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}

// GenericApplicationContext
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException {

this.beanFactory.registerBeanDefinition(beanName, beanDefinition);
}

@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException {

Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");

if (beanDefinition instanceof AbstractBeanDefinition abd) {
try {
abd.validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}

// 检查是否已有同名的bean被注册过了
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
if (existingDefinition != null) {
if (!isBeanDefinitionOverridable(beanName)) {
throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
}
else if (existingDefinition.getRole() < beanDefinition.getRole()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
// 如果允许覆盖注册,且当前bean的级别高于已注册的bean(比如已注册的是一个应用自己的bean,但是现在正在注册一个框架提供的bean),
// 那么就继续
if (logger.isInfoEnabled()) {
logger.info("Overriding user-defined bean definition for bean '" + beanName +
"' with a framework-generated bean definition: replacing [" +
existingDefinition + "] with [" + beanDefinition + "]");
}
}
else if (!beanDefinition.equals(existingDefinition)) {
if (logger.isDebugEnabled()) {
logger.debug("Overriding bean definition for bean '" + beanName +
"' with a different definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
else {
if (logger.isTraceEnabled()) {
logger.trace("Overriding bean definition for bean '" + beanName +
"' with an equivalent definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
// 覆盖beanDefinitionMap中原有的bean
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
if (isAlias(beanName)) {
String aliasedName = canonicalName(beanName);
if (!isBeanDefinitionOverridable(aliasedName)) {
if (containsBeanDefinition(aliasedName)) { // alias for existing bean definition
throw new BeanDefinitionOverrideException(
beanName, beanDefinition, getBeanDefinition(aliasedName));
}
else { // alias pointing to non-existing bean definition
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Cannot register bean definition for bean '" + beanName +
"' since there is already an alias for bean '" + aliasedName + "' bound.");
}
}
else {
removeAlias(beanName);
}
}
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
synchronized (this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
removeManualSingletonName(beanName);
}
}
else {
// Still in startup registration phase
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
removeManualSingletonName(beanName);
}
this.frozenBeanDefinitionNames = null;
}

if (existingDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
else if (isConfigurationFrozen()) {
clearByTypeCache();
}
}

在启动的时候,实际会走到 registerBeanDefinition 方法的 // Still in startup registration phase 这部分。这里会把传进来的 BeanDefinition 注册到 beanDefinitionMap 中然后返回。

刷新 application context

在创建 application context 之后,Spring Boot 会刷新它。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
private void refreshContext(ConfigurableApplicationContext context) {
if (this.registerShutdownHook) {
shutdownHook.registerApplicationContext(context);
}
refresh(context);
}

protected void refresh(ConfigurableApplicationContext applicationContext) {
applicationContext.refresh();
}

// ServletWebServerApplicationContext
public final void refresh() throws BeansException, IllegalStateException {
try {
super.refresh();
}
catch (RuntimeException ex) {
WebServer webServer = this.webServer;
if (webServer != null) {
webServer.stop();
webServer.destroy();
}
throw ex;
}
}

// AbstractApplicationContext
public void refresh() throws BeansException, IllegalStateException {
this.startupShutdownLock.lock();
try {
this.startupShutdownThread = Thread.currentThread();

StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

// Prepare this context for refreshing.
// 注入listener等组件,激活application context
prepareRefresh();

// Tell the subclass to refresh the internal bean factory.
// 得到当前application context的bean factory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

// Prepare the bean factory for use in this context.
// 初始化bean factory,包括设定class loader,注入各种组件等
prepareBeanFactory(beanFactory);

try {
// Allows post-processing of the bean factory in context subclasses.
// 设置beanFactory的后置处理
postProcessBeanFactory(beanFactory);

StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
// Invoke factory processors registered as beans in the context.
// 调用beanFactory的后置处理
invokeBeanFactoryPostProcessors(beanFactory);

// Register bean processors that intercept bean creation.
// 注册bean的后处理器
registerBeanPostProcessors(beanFactory);
beanPostProcess.end();

// Initialize message source for this context.
initMessageSource();

// Initialize event multicaster for this context.
initApplicationEventMulticaster();

// Initialize other special beans in specific context subclasses.
// 创建web server
onRefresh();

// Check for listener beans and register them.
// 把listener beans注入到容器
registerListeners();

// Instantiate all remaining (non-lazy-init) singletons.
// 把剩余尚未实例化的bean实例化
finishBeanFactoryInitialization(beanFactory);

// Last step: publish corresponding event.
// 发布application context刷新完成的事件
finishRefresh();
}

catch (RuntimeException | Error ex ) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}

// Destroy already created singletons to avoid dangling resources.
destroyBeans();

// Reset 'active' flag.
cancelRefresh(ex);

// Propagate exception to caller.
throw ex;
}

finally {
contextRefresh.end();
}
}
finally {
this.startupShutdownThread = null;
this.startupShutdownLock.unlock();
}
}

这里首先会一路走到 AbstractApplicationContext#refresh 方法,完成初始化 bean factory,实例化剩余的 bean 等操作。

得到当前 application context 的 bean factory

点进 obtainFreshBeanFactory 方法可以看到这样的实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// AbstractApplicationContext
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
return getBeanFactory();
}

// GenericApplicationContext
private final AtomicBoolean refreshed = new AtomicBoolean();

@Override
protected final void refreshBeanFactory() throws IllegalStateException {
if (!this.refreshed.compareAndSet(false, true)) {
throw new IllegalStateException(
"GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");
}
this.beanFactory.setSerializationId(getId());
}

@Override
public final ConfigurableListableBeanFactory getBeanFactory() {
return this.beanFactory;
}

refreshBeanFactory 方法中,Spring 会利用 AtomicBooleancompareAndSet 方法来保证这个方法绝对只会被执行一次。

调用 beanFactory 的后置处理

invokeBeanFactoryPostProcessors 这里会完成 IoC 容器初始化的三个步骤,分别是

  • Resource 定位
    在前面 Spring Boot 已经得到了启动类的 BeanDefinition,那么在这里它会解析启动类的 BeanDefinition,得到启动类所在的包并将其作为 basePackage,这就完成了定位的过程。
    此外 Spring Boot 的各种 starter 是通过 SPI 机制实现的自动装配,而自动装配也是在这个方法中完成的。
    还有就是,这个方法中也会处理 @EnableXXX 注解中通过 @Import 指定的配置类。
  • BeanDefinition 载入
    在上一步得到了 basePackage 后,Spring Boot 会把路径拼接成 classpath*:com/example/demo/**/*.class 这样的形式,然后 PathMatchingResourcePatternResolver 类会把这个路径下所有的 class 都加载进来,然后遍历判断有没有 @Component 注解。因为 @Controller@Service@Configuration 之类的实际上只是把 @Component 又包了一层,所以不用单独扫描它们。
  • 注册 BeanDefinition
    在这一步,BeanDefinitionRegister 接口的实现类会把解析到的 BeanDefinition 向 IoC 容器注册。

这部分实在是太长,而本文又已经够长了,所以我会单开一篇来细说。

把剩余尚未实例化的 bean 实例化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// Initialize conversion service for this context.
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
beanFactory.setConversionService(
beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
}

// Register a default embedded value resolver if no BeanFactoryPostProcessor
// (such as a PropertySourcesPlaceholderConfigurer bean) registered any before:
// at this point, primarily for resolution in annotation attribute values.
if (!beanFactory.hasEmbeddedValueResolver()) {
beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
}

// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
for (String weaverAwareName : weaverAwareNames) {
getBean(weaverAwareName);
}

// Stop using the temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(null);

// Allow for caching all bean definition metadata, not expecting further changes.
// 冻结bean definition,不再允许新的修改
beanFactory.freezeConfiguration();

// Instantiate all remaining (non-lazy-init) singletons.
// 开始实例化bean
beanFactory.preInstantiateSingletons();
}

public void preInstantiateSingletons() throws BeansException {
if (logger.isTraceEnabled()) {
logger.trace("Pre-instantiating singletons in " + this);
}

// Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

// Trigger initialization of all non-lazy singleton beans...
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof SmartFactoryBean<?> smartFactoryBean && smartFactoryBean.isEagerInit()) {
getBean(beanName);
}
}
else {
getBean(beanName);
}
}
}

// Trigger post-initialization callback for all applicable beans...
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton smartSingleton) {
StartupStep smartInitialize = getApplicationStartup().start("spring.beans.smart-initialize")
.tag("beanName", beanName);
smartSingleton.afterSingletonsInstantiated();
smartInitialize.end();
}
}
}

第一个 for 循环的重点在于 getBean 方法,逐层点进实现,最终会进入 AbstractBeanFactory#doGetBean 方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
protected <T> T doGetBean(
String name,
@Nullable Class<T> requiredType,
@Nullable Object[] args,
boolean typeCheckOnly
) throws BeansException {

String beanName = transformedBeanName(name);
Object beanInstance;

// Eagerly check singleton cache for manually registered singletons.
// 先检查这个bean是不是一个已经注册过的singleton,并尝试获取
// 如果它已经注册过,但是尚未实例化的话,
// 这个方法会将其实例化并返回。
// 方法里面是一个复杂的双检锁单例模式。
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isTraceEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
}
}
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
// 如果这个bean不是singleton
else {
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}

// Check if bean definition exists in this factory.
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
String nameToLookup = originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory abf) {
return abf.doGetBean(nameToLookup, requiredType, args, typeCheckOnly);
}
else if (args != null) {
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else if (requiredType != null) {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
else {
return (T) parentBeanFactory.getBean(nameToLookup);
}
}

if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}

StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate")
.tag("beanName", name);
try {
if (requiredType != null) {
beanCreation.tag("beanType", requiredType::toString);
}
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);

// Guarantee initialization of beans that the current bean depends on.
// 先把这个bean所依赖的bean初始化好
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
// 如果被依赖的bean也依赖它,那就循环依赖了,没法处理,抛异常
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
registerDependentBean(dep, beanName);
try {
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}

// Create bean instance.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
// 创建并注册这个singleton bean
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}

else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}

else {
String scopeName = mbd.getScope();
if (!StringUtils.hasLength(scopeName)) {
throw new IllegalStateException("No scope name defined for bean '" + beanName + "'");
}
Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new ScopeNotActiveException(beanName, scopeName, ex);
}
}
}
catch (BeansException ex) {
beanCreation.tag("exception", ex.getClass().toString());
beanCreation.tag("message", String.valueOf(ex.getMessage()));
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
finally {
beanCreation.end();
if (!isCacheBeanMetadata()) {
clearMergedBeanDefinition(beanName);
}
}
}

return adaptBeanInstance(name, beanInstance, requiredType);
}

启动部分的收尾工作

在完成刷新 application context 之后,Spring Boot 会发布 ApplicationStartedEventApplicationReadyEvent 事件,调用各个 Runner,然后应用正式启动开始运行

参考文章

  • spring boot 启动流程分析
  • spring boot 中的 spring factories 机制
  • 应用启动过程 —— 准备应用上下文
  • 应用启动过程 ——BootstrapContext
  • SpringApplication 中文文档
  • Spring Boot 应用 Main 函数入口 Primary Source
  • Spring 源码分析之 ConversionService
  • Spring ConversionService 类型转换(一)Converter
  • 走心 Springboot 源码解析: 三、prepareEnvironment () 环境配置 解析配置文件信息