主程序入口

这里补充 入口 携带的注解说明

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

构造方法

1
2
3
4
5
6
7
8
9
10
org.springframework.boot.SpringApplication
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();
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
WebApplicationType#deduceFromClasspath

这段代码是用于从类路径中推断出静态的Web应用程序类型的。它通过检查类路径中是否存在特定的类来确定应用程序类型。

首先,它检查是否存在WEBFLUX_INDICATOR_CLASS类,并且不存在WEBMVC_INDICATOR_CLASSJERSEY_INDICATOR_CLASS类。如果满足这个条件,那么应用程序类型被判断为WebApplicationType.REACTIVE,表示是一个基于响应式编程模型的Web应用程序。

接下来,它遍历SERVLET_INDICATOR_CLASSES列表中的类名。如果在类路径中找不到其中任何一个类,那么应用程序类型被判断为WebApplicationType.NONE,表示不是一个基于Servlet的Web应用程序。

如果以上两个条件都不满足,那么应用程序类型被判断为WebApplicationType.SERVLET,表示是一个基于Servlet的Web应用程序。

WebApplicationType是一个枚举类型,用于表示Web应用程序的类型,包括NONESERVLETREACTIVE

1
2
3
4
5
6
7
8
9
10
11
12
static WebApplicationType deduceFromClasspath() {
if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
return WebApplicationType.REACTIVE;
}
for (String className : SERVLET_INDICATOR_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
return WebApplicationType.SERVLET;
}

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
47
48
49
50
51
52
53
54
55
56
57
58
59
org.springframework.boot.SpringApplication
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
// 创建应用上下文
ConfigurableApplicationContext context = null;
// 异常收集,报告启动异常
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
// 设置为headless模式
this.configureHeadlessProperty();
// 获取事件监听器,负责产生事件
SpringApplicationRunListeners listeners = this.getRunListeners(args);
// 发布一个启动事件 ApplicationStartingEvent 告知上述所有监听器
listeners.starting();

Collection exceptionReporters;
try {
// 配置应用参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 准备应用程序的环境
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
// 配置禁用BeanInfo
this.configureIgnoreBeanInfo(environment);
// 打印 banner
Banner printedBanner = this.printBanner(environment);
// 使用策略模式创建应用上下文
context = this.createApplicationContext();
// 获取所有实现了 SpringBootExceptionReporter 接口的实例,并注册到 应用上下文中
exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
// 准备程序上下文
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
// 刷新应用程序上下文
this.refreshContext(context);
// 空实现
this.afterRefresh(context, applicationArguments);
// 记录启动消耗的时间
stopWatch.stop();
if (this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
}
// 发布 ApplicationStartedEvent 事件
listeners.started(context);
this.callRunners(context, applicationArguments);
} catch (Throwable var10) {
// 异常处理
this.handleRunFailure(context, var10, exceptionReporters, listeners);
throw new IllegalStateException(var10);
}

try {
// 发布一个 ApplicationReadyEvent 事件
listeners.running(context);
return context;
} catch (Throwable var9) {
// 异常处理
this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
throw new IllegalStateException(var9);
}
}
SpringApplication#getRunListeners

springAllicationRunListenerSpringApplicationrun方法的监听器。springAllicationRunListener通过springFactoriesLoader加载,且必须声明一个公共的构造函数,接收SpringApplication实例和string[]参数,每次运行时都会创建一个实例。

SpringApplicationRunListener提供了一系列方法,用户可以通过回调这些方法,在各个启动流程时,加入指定的处理逻辑:

1
2
3
4
5
6
7
private SpringApplicationRunListeners getRunListeners(String[] args) {
// 构造clazz数组
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
// 调用SpringApplicationRunListeners构造方法
return new SpringApplicationRunListeners(logger,
getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}
1
2
3
4
SpringApplicationRunListeners(Log log, Collection<? extends SpringApplicationRunListener> listeners) {
this.log = log;
this.listeners = new ArrayList<>(listeners);
}

SpringApplicationRunListeners构造方法的第二个参数是集合类型的listeners,通过调用getSpringFactoriesInstances获取。

SpringApplicationRunListeners#getSpringFactoriesInstances

getSpringFactoriesInstances是用来获取factories配置文件中的注册类,并进行实例化操作。

SpringApplicationRunListeners通过SpringFactoriesLoader进行加载

1
2
3
4
5
6
7
8
9
10
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = getClassLoader();
// Use names and ensure unique to protect against duplicates
// 获取 META-INF/spring.factories 中对应的配置
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
// 创建 springFactory 实例
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
SpringApplicationRunListeners#createSpringFactoriesInstances

创建springFactories实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes,
ClassLoader classLoader, Object[] args, Set<String> names) {
List<T> instances = new ArrayList<>(names.size());
for (String name : names) {
try {
Class<?> instanceClass = ClassUtils.forName(name, classLoader);
Assert.isAssignable(type, instanceClass);
// 获取有参构造器
Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
// 实例化 springFactory实例
T instance = (T) BeanUtils.instantiateClass(constructor, args);
instances.add(instance);
}
catch (Throwable ex) {
throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex);
}
}
return instances;
}

EventPublishingRunListener

EventPublishingRunListenerspringboot针对springAllicationRunListener接口内置的唯一实现。

它使用内置的SimpleApplicationEventMulticaster 来广播在上下文刷新之前触发的事件。

默认情况下,Spring Boot在初始化过程中触发的事件也是交由EventPublishingRunListener来代理实现的。 其构造方法如下:

1
2
3
4
5
6
7
8
public EventPublishingRunListener(SpringApplication application, String[] args) {
this.application = application;
this.args = args;
this.initialMulticaster = new SimpleApplicationEventMulticaster();
for (ApplicationListener<?> listener : application.getListeners()) {
this.initialMulticaster.addApplicationListener(listener);
}
}

springboot完成基本初始化之后,会遍历springapplication的所有applicationListener实例,并将它们与SimpleApplicationEventMulticaster 进行关联,方便启动过程中将时间传递给所有监听器。

spring事件推送原理

SpringApplication#prepareEnvironment

  1. 加载并解析配置文件:在启动过程中,Spring会加载应用程序的配置文件,如application.properties或application.yml。prepareEnvironment方法负责加载这些配置文件,并将其解析为Spring框架内部可以理解的数据结构。
  2. 配置环境属性:prepareEnvironment方法还负责配置应用程序的环境属性。这些属性可以通过Environment对象访问,用于在应用程序的不同部分共享配置信息。例如,可以通过环境属性指定数据库连接的URL、用户名和密码等。
  3. 配置配置源:prepareEnvironment方法还负责配置Spring框架的配置源。配置源是指Spring框架用于获取配置信息的来源,可以是XML配置文件、注解或Java配置类等。通过配置源,Spring可以了解应用程序的组件定义、依赖关系和其他配置信息。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// // 按照主程序中定义的 应用类型 设置 应用环境
ConfigurableEnvironment environment = getOrCreateEnvironment();
// 将配置参数设置到 应用环境中
configureEnvironment(environment, applicationArguments.getSourceArgs());
ConfigurationPropertySources.attach(environment);
// 发布 ApplicationEnvironmentPreparedEvent 事件,通知 ConfigFileApplicationListener.onApplicationEvent -> postProcessEnvironment
listeners.environmentPrepared(environment);
// 将 当前环境配置 与spring应用 相绑定
bindToSpringApplication(environment);
// 检查是否需要转换环境
if (!this.isCustomEnvironment) {
environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
deduceEnvironmentClass());
}
// 将 environment中的属性源 赋给 springboot的配置属性源
ConfigurationPropertySources.attach(environment);
return environment;
}

ConfigFileApplicationListener.onApplicationEvent -> postProcessEnvironment中加载application.yml 配置 addPropertySources

1
ConfigFileApplicationListener.onApplicationEvent -> postProcessEnvironment

SpringApplication#deduceEnvironmentClass

1
2
3
4
5
6
7
8
9
10
private Class<? extends StandardEnvironment> deduceEnvironmentClass() {
switch (this.webApplicationType) {
case SERVLET:
return StandardServletEnvironment.class;
case REACTIVE:
return StandardReactiveWebEnvironment.class;
default:
return StandardEnvironment.class;
}
}

SpringApplication#getSpringFactoriesInstances

用于从META-INF/spring.factories文件中获取指定类型的所有实现类。在这里,它会获取所有实现了SpringBootExceptionReporter接口的类的实例。

1
2
3
4
5
6
7
8
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = getClassLoader();
// Use names and ensure unique to protect against duplicates
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}

SpringApplication#prepareContext

  1. 加载应用程序配置文件,包括 application.propertiesapplication.yml
  2. 注册应用程序事件监听器。
  3. 解析命令行参数并将其存储在应用程序参数对象中。
  4. 打印应用程序启动横幅信息。

1696985455028

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
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {

context.setEnvironment(environment);
postProcessApplicationContext(context);
// 调用ApplicationContextInitializer#initialize
applyInitializers(context);
// 发布 ApplicationContextInitializedEvent 事件
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// 获取 ConfigurableListableBeanFactory 并注册一个 springApplicationArguments bean
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
// bean 重名时是否允许重写
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
// 根据配置确定是否要填充懒加载的 BeanFactoryPostProcessor
if (this.lazyInitialization) {
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
// 获取启动类
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[0]));
// 发布 ApplicationPreparedEvent 事件
listeners.contextLoaded(context);
}

SpringApplication#load

加载beans到应用上下文

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
/**
* Load beans into the application context.
* @param context the context to load beans into
* @param sources the sources to load
*/
protected void load(ApplicationContext context, Object[] sources) {
if (logger.isDebugEnabled()) {
logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
}
// 初始化 BeanDefinitionLoader
BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);
// 为潜在的 reader/scanner 配置 BeanNameGenerator
if (this.beanNameGenerator != null) {
loader.setBeanNameGenerator(this.beanNameGenerator);
}
// 为潜在的 reader/scanner 配置 ResourceLoader
if (this.resourceLoader != null) {
loader.setResourceLoader(this.resourceLoader);
}
// 为 BeanDefinitionLoader (潜在的 reader/scanner)配置 环境
if (this.environment != null) {
loader.setEnvironment(this.environment);
}
// 加载启动类,将启动类注入到容器中, [可以继续往下挖]
loader.load();
}

1696984777872

BeanDefinitionLoader#loader.load#

根据不同的源类型加载配置文件

  • 如果源对象是 Class 类型,则调用 load(Class<?> clazz) 方法加载配置文件。
  • 如果源对象是 Resource 类型,则调用 load(Resource resource) 方法加载配置文件。
  • 如果源对象是 Package 类型,则调用 load(Package pkg) 方法加载配置文件。
  • 如果源对象是 CharSequence 类型,则调用 load(CharSequence content) 方法加载配置文件。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private int load(Object source) {
Assert.notNull(source, "Source must not be null");
if (source instanceof Class<?>) {
return load((Class<?>) source);
}
if (source instanceof Resource) {
return load((Resource) source);
}
if (source instanceof Package) {
return load((Package) source);
}
if (source instanceof CharSequence) {
return load((CharSequence) source);
}
throw new IllegalArgumentException("Invalid source type " + source.getClass());
}
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
private int 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);
load(loader);
}
if (isEligible(source)) {
this.annotatedReader.register(source);
return 1;
}
return 0;
}

/**
* Register one or more component classes to be processed.
* <p>Calls to {@code register} are idempotent; adding the same
* component class more than once has no additional effect.
* @param componentClasses one or more component classes,
* e.g. {@link Configuration @Configuration} classes
*/
public void register(Class<?>... componentClasses) {
for (Class<?> componentClass : componentClasses) {
registerBean(componentClass);
}
}
AnnotatedBeanDefinitionReader#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
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.setInstanceSupplier(supplier);
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
abd.setScope(scopeMetadata.getScopeName());
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));

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);
}

SpringApplication#refreshContext

  1. 创建并初始化 BeanFactory:首先,它会创建一个 BeanFactory 对象,用于管理和创建应用程序中的 Bean。
  2. 加载 Bean 定义:接下来,它会加载应用程序中定义的 Bean,包括通过注解、XML 配置文件等方式定义的 Bean。
  3. 实例化和初始化 Bean:然后,它会实例化和初始化所有的 Bean,包括依赖注入、AOP 代理等操作。
  4. 处理 Bean 生命周期回调:在 Bean 实例化和初始化完成后,refresh 方法会调用各个 Bean 的生命周期回调方法,例如 @PostConstruct 注解标注的方法。
  5. 注册 Bean 后置处理器:refresh 方法还会注册 Bean 后置处理器,用于在 Bean 初始化前后进行一些额外的处理操作。

通过调用 SpringApplication#refresh 方法,应用程序上下文将完成初始化和刷新,所有的 Bean 将被正确创建和配置,应用程序将进入可用状态,可以响应外部请求。

具体内容我放到另外一篇博文中了springboot源码之启动流程2

1
2
3
4
5
6
7
8
9
10
11
12
private void refreshContext(ConfigurableApplicationContext context) {
refresh((ApplicationContext) context);
if (this.registerShutdownHook) {
try {
// 注册 关闭 钩子
context.registerShutdownHook();
}
catch (AccessControlException ex) {
// Not allowed in some environments.
}
}
}
SpringApplication#callRunners

spring callRunners(context, applicationArguments) 是 Spring Boot 中的一个方法,用于执行在应用程序启动时需要运行的 ApplicationRunnerCommandLineRunner 接口的实现类。

在 Spring Boot 应用程序启动时,可以通过实现 ApplicationRunnerCommandLineRunner 接口来定义一些需要在应用程序启动后立即执行的逻辑。这些逻辑可以包括初始化数据、加载配置、启动定时任务等。

callRunners(context, applicationArguments) 方法会在 Spring Boot 应用程序启动时被调用,它会获取所有实现了 ApplicationRunnerCommandLineRunner 接口的 Bean,并按照优先级顺序依次执行它们的 run 方法。通过调用这些方法,可以在应用程序启动时执行一些自定义的逻辑。

context 参数是 Spring 应用程序的上下文,它包含了应用程序中所有的 Bean。applicationArguments 参数是应用程序的命令行参数,可以通过它获取命令行传递的参数值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
private void callRunners(ApplicationContext context, ApplicationArguments args) {
List<Object> runners = new ArrayList<>();
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) {
callRunner((ApplicationRunner) runner, args);
}
if (runner instanceof CommandLineRunner) {
callRunner((CommandLineRunner) runner, args);
}
}
}

environment的区别

1
2
3
4
5
6
7
8
9
10
11
12
13
private ConfigurableEnvironment getOrCreateEnvironment() {
if (this.environment != null) {
return this.environment;
}
switch (this.webApplicationType) {
case SERVLET:
return new StandardServletEnvironment();
case REACTIVE:
return new StandardReactiveWebEnvironment();
default:
return new StandardEnvironment();
}
}

三级缓存

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
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// Quick check for existing instance without full singleton lock
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
synchronized (this.singletonObjects) {
// Consistent creation of early reference within full singleton lock
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
return singletonObject;
}

引用

1. spring三级缓存
2. springbean装配过程
3. Spring 的 InstantiationAware 后处理器
4. 为什么JDK动态代理只能代理接口,不能直接代理类?CGlib为什么可以代理类?
5. SpringBoot的启动流程