目录
一、背景
上一篇我们解读了创建应用上下文,本篇主要解读准备应用上下文,首先我们还是先回顾下启动的整体流程。
1.1、run方法整体流程
接下来的几个方法所在类的具体路径:org.springframework.boot.SpringApplication
public ConfigurableApplicationContext run(String... args) {
// 1、记录启动的开始时间(单位纳秒)
long startTime = System.nanoTime();
// 2、初始化启动上下文、初始化应用上下文
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
ConfigurableApplicationContext context = null;
// 3、设置无头属性:“java.awt.headless”,默认值为:true(没有图形化界面)
configureHeadlessProperty();
// 4、获取所有 Spring 运行监听器
SpringApplicationRunListeners listeners = getRunListeners(args);
// 发布应用启动事件
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
// 5、初始化默认应用参数类(命令行参数)
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 6、根据运行监听器和应用参数 来准备 Spring 环境
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
// 配置忽略bean信息
configureIgnoreBeanInfo(environment);
// 7、创建 Banner 并打印
Banner printedBanner = printBanner(environment);
// 8、创建应用上下文
context = createApplicationContext();
// 设置applicationStartup
context.setApplicationStartup(this.applicationStartup);
// 9、准备应用上下文
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
// 10、刷新应用上下文(核心)
refreshContext(context);
// 11、应用上下文刷新后置处理
afterRefresh(context, applicationArguments);
// 13、时间信息、输出日志记录执行主类名
Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
}
// 14、发布应用上下文启动完成事件
listeners.started(context, timeTakenToStartup);
// 15、执行所有 Runner 运行器
callRunners(context, applicationArguments);
} catch (Throwable ex) {
// 运行错误处理
handleRunFailure(context, ex, listeners);
throw new IllegalStateException(ex);
}
try {
// 16、发布应用上下文就绪事件(可以使用了)
Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
listeners.ready(context, timeTakenToReady);
} catch (Throwable ex) {
// 运行错误处理
handleRunFailure(context, ex, null);
throw new IllegalStateException(ex);
}
// 17、返回应用上下文
return context;
}
1.2、本文解读范围
args 是启动Spring应用的命令行参数,该参数可以在Spring应用中被访问。本文主要讲解到命令行参数的解析,也就是:
// 9、准备应用上下文
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
二、准备应用上下文
2.1、整体流程
此方法所在类的具体路径:org.springframework.boot.SpringApplication
private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
// 设置环境
context.setEnvironment(environment);
// 对应用上下文进行后置处理
postProcessApplicationContext(context);
// 应用所有初始化器
applyInitializers(context);
// 发布应用上下文准备事件(ApplicationContextInitializedEvent)
listeners.contextPrepared(context);
//
bootstrapContext.close(context);
if (this.logStartupInfo) {
// 日志启动信息
logStartupInfo(context.getParent() == null);
// 日志启动配置文件信息
logStartupProfileInfo(context);
}
// 获取beanFactory,此处是(DefaultListableBeanFactory) 添加特定于引导的单例bean
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
// 注册一个单例bean,bean名称是springApplicationArguments
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
// 如果printedBanner 不为空,注册成单例bean,bean名称是springBootBanner
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
// 判断是否为AbstractAutowireCapableBeanFactory的实例
if (beanFactory instanceof AbstractAutowireCapableBeanFactory) {
// 是就设置是否允许bean定义重写,此处的allowBeanDefinitionOverriding 默认为false
// 需要注意的是DefaultListableBeanFactory里的allowBeanDefinitionOverriding 默认是true
((AbstractAutowireCapableBeanFactory) beanFactory).setAllowCircularReferences(this.allowCircularReferences);
// 判断是否为DefaultListableBeanFactory的实例
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
}
// 默认是false
if (this.lazyInitialization) {
// 懒加载beanFactory 后置处理
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
// 加载资源
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
// 加载主类
load(context, sources.toArray(new Object[0]));
// 发布应用上下文加载完毕的事件
listeners.contextLoaded(context);
}
2.2、设置环境
此方法所在类的具体路径:org.springframework.boot.SpringApplication
public class AnnotationConfigServletWebServerApplicationContext extends ServletWebServerApplicationContext
implements AnnotationConfigRegistry {
private final AnnotatedBeanDefinitionReader reader;
private final ClassPathBeanDefinitionScanner scanner;
@Override
public void setEnvironment(ConfigurableEnvironment environment) {
// 设置父类环境
super.setEnvironment(environment);
// 设置带注释的Bean定义读取器的环境
this.reader.setEnvironment(environment);
// 设置类路径Bean定义扫描器的环境
this.scanner.setEnvironment(environment);
}
}
此处的环境environment是ApplicationServletEnvironment,设置父类环境,就是设置AbstractApplicationContext 的环境变量,AnnotatedBeanDefinitionReader 和 ClassPathBeanDefinitionScanner 的初始化在我上一篇文章里讲了,具体参考:Alian解读SpringBoot 2.6.0 源码(六):启动流程分析之创建应用上下文;AnnotatedBeanDefinitionReader 的环境设置,还包括条件上下文ConditionContext 里的参数设置;ClassPathBeanDefinitionScanner 的环境变量设置
2.3、应用上下文进行后置处理
此方法所在类的具体路径:org.springframework.boot.SpringApplication
private boolean addConversionService = true;
private ResourceLoader resourceLoader;
private BeanNameGenerator beanNameGenerator;
public static final String CONFIGURATION_BEAN_NAME_GENERATOR =
"org.springframework.context.annotation.internalConfigurationBeanNameGenerator";
protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
// 判断beanNameGenerator 是否为空
if (this.beanNameGenerator != null) {
// 不为空则注册单例bean,bean的名称为:org.springframework.context.annotation.internalConfigurationBeanNameGenerator
context.getBeanFactory().registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
this.beanNameGenerator);
}
// 判断资源加载器是否为空,此处的resourceLoader默认为null
if (this.resourceLoader != null) {
// 资源加载器不为空
// 判断应用上下文是否是GenericApplicationContext的实例
if (context instanceof GenericApplicationContext) {
((GenericApplicationContext) context).setResourceLoader(this.resourceLoader);
}
// 判断应用上下文是否是DefaultResourceLoader的实例
if (context instanceof DefaultResourceLoader) {
((DefaultResourceLoader) context).setClassLoader(this.resourceLoader.getClassLoader());
}
}
// addConversionService默认为true
if (this.addConversionService) {
// ConversionService在我们之前环境准备就讲过了
context.getBeanFactory().setConversionService(context.getEnvironment().getConversionService());
}
}
应用上下文进行后置处理中,主要是设置了一个转换服务ConversionService,这个转换服务我们在之前的文章里讲过了,具体参考:Alian解读SpringBoot 2.6.0 源码(四):启动流程分析之应用环境准备 里的章节 2.3、配置环境。
2.4、应用所有初始化器
此方法所在类的具体路径:
private List<ApplicationContextInitializer<?>> initializers;
protected void applyInitializers(ConfigurableApplicationContext context) {
// 这里获取的初始化器,就是SpringApplication对象创建时获取的那7个
for (ApplicationContextInitializer initializer : getInitializers()) {
// 解析得到参数类型
Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
ApplicationContextInitializer.class);
Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
// 调用initialize
initializer.initialize(context);
}
}
public Set<ApplicationContextInitializer<?>> getInitializers() {
// 返回不可修改的有序集合
return asUnmodifiableOrderedSet(this.initializers);
}
这里获取的初始化器,就是SpringApplication对象创建时获取的那7个,这里会遍历这些初始化器,然后调用它们的initialize这里对它们实现的功能作一个简单的概括(有兴趣的可以去debug下):
| 初始化器 | 功能说明 |
|---|---|
| DelegatingApplicationContextInitializer | 从context中得到env,从env中得到配置context.initializer.classes的class对象集合,如果不为空,则实例化List中的对象然后调用initialize方法 |
| SharedMetadataReaderFactoryContextInitializer | 给应用上下文添加了一个CachingMetadataReaderFactoryPostProcessor后置处理类 |
| ContextIdApplicationContextInitializer | 获取ContextId对象,设置应用上下文id,BeanFactory注册一个ContextId |
| ConfigurationWarningsApplicationContextInitializer | 给应用上下文添加了一个ConfigurationWarningsPostProcessor后置处理类 |
| RSocketPortInfoApplicationContextInitializer | 给应用上下文添加了一个静态内部Listener,该类实现了ApplicationContextInitializer和ApplicationListener接口 |
| ServerPortInfoApplicationContextInitializer | 给应用上下文添加一个ServerPortInfoApplicationContextInitializer,监听WebServerInitializedEvent事件 |
| ConditionEvaluationReportLoggingListener | 给应用上下文添加一个监听ConditionEvaluationReportListener,并监听ContextRefreshedEvent和ApplicationFailedEvent事件 |
2.5、发布应用上下文准备事件
说到这里,实际上只要看我之前文章,应该对流程会非常的熟悉。不管样,我们再简单过一下流程。
2.5.1、遍历运行监听器
此方法所在类的具体路径:org.springframework.boot.SpringApplicationRunListeners
class SpringApplicationRunListeners {
private final List<SpringApplicationRunListener> listeners;
void contextPrepared(ConfigurableApplicationContext context) {
doWithListeners("spring.boot.application.context-prepared", (listener) -> listener.contextPrepared(context));
}
private void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction) {
doWithListeners(stepName, listenerAction, null);
}
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();
}
}
之前的文章就知道了,这里的运行监听器就一个,那就是EventPublishingRunListener,接下里就是去看看事件发布运行监听器的准备应用上下文事件做了什么。
2.5.2、事件发布运行监听器
此方法所在类的具体路径:org.springframework.boot.context.event.EventPublishingRunListener
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
private final SimpleApplicationEventMulticaster initialMulticaster;
@Override
public void contextPrepared(ConfigurableApplicationContext context) {
// 交给事件广播器处理
this.initialMulticaster.multicastEvent(
// 实例化ApplicationContextInitializedEvent
new ApplicationContextInitializedEvent(this.application, this.args, context));
}
}
- 实例化ApplicationContextInitializedEvent
- 通过事件广播器发布事件
2.5.3、事件广播器
此方法所在类的具体路径:org.springframework.context.event.SimpleApplicationEventMulticaster
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
@Override
public void multicastEvent(ApplicationEvent event) {
// 通过事件解析事件类型
// 广播事件
multicastEvent(event, resolveDefaultEventType(event));
}
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
// executor默认为null
Executor executor = getTaskExecutor();
// 根据事件和事件类型获取监听器列表
// 然后遍历监听器列表,分别调用监听器的方法
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
} else {
// 调用
invokeListener(listener, event);
}
}
}
}
- 首先根据事件解析事件的类型(这里的事件是ApplicationContextInitializedEvent)
- 根据事件和事件类型进行事件广播
- 根据事件和事件类型获取事件监听器列表
2.5.4、获取符合事件的监听器
这里调用getApplicationListeners(event, type)方法,实际就是调用抽象类AbstractApplicationEventMulticaster中的getApplicationListeners方法,最终匹配到的监听器结果:
- BackgroundPreinitializer
- DelegatingApplicationListener
也符合我们下面这个对照表:
| 监听器 | 对应的事件 |
|---|---|
| AnsiOutputApplicationListener | ApplicationEnvironmentPreparedEvent |
| BackgroundPreinitializer | SpringApplicationEvent |
| ClearCachesApplicationListener | ContextRefreshedEvent |
| DelegatingApplicationListener | ApplicationEvent |
| EnvironmentPostProcessorApplicationListener | ApplicationEnvironmentPreparedEvent、ApplicationPreparedEvent、ApplicationFailedEvent |
| FileEncodingApplicationListener | ApplicationEnvironmentPreparedEvent |
| LoggingApplicationListener | ApplicationStartingEvent、ApplicationEnvironmentPreparedEvent、ApplicationPreparedEvent、 ContextClosedEvent、ApplicationFailedEvent |
| ParentContextCloserApplicationListener | ParentContextAvailableEvent |
debug进去,这里两个监听器什么都没有做。
2.6、日志打印
此方法所在类的具体路径:org.springframework.boot.SpringApplication
2.6.1、启动日志
protected void logStartupInfo(boolean isRoot) {
if (isRoot) {
new StartupInfoLogger(this.mainApplicationClass).logStarting(getApplicationLog());
}
}
此方法所在类的具体路径:org.springframework.boot.StartupInfoLogger
class StartupInfoLogger {
void logStarting(Log applicationLog) {
Assert.notNull(applicationLog, "Log must not be null");
applicationLog.info(LogMessage.of(this::getStartingMessage));
applicationLog.debug(LogMessage.of(this::getRunningMessage));
}
private CharSequence getStartingMessage() {
StringBuilder message = new StringBuilder();
message.append("Starting ");
appendApplicationName(message);
appendVersion(message, this.sourceClass);
appendJavaVersion(message);
appendOn(message);
appendPid(message);
appendContext(message);
return message;
}
private CharSequence getRunningMessage() {
StringBuilder message = new StringBuilder();
message.append("Running with Spring Boot");
appendVersion(message, getClass());
message.append(", Spring");
appendVersion(message, ApplicationContext.class);
return message;
}
}
其实就相当于控制台输出如下日志:
Starting SpringbootApplication using Java 1.8.0_111 on DESKTOP-EIGL04G with PID 3892 (C:\workspace\study\springboot\target\classes started by admin in C:\workspace\study\springboot)
2.6.2、启动配置日志
protected void logStartupProfileInfo(ConfigurableApplicationContext context) {
Log log = getApplicationLog();
if (log.isInfoEnabled()) {
String[] activeProfiles = context.getEnvironment().getActiveProfiles();
if (ObjectUtils.isEmpty(activeProfiles)) {
String[] defaultProfiles = context.getEnvironment().getDefaultProfiles();
log.info("No active profile set, falling back to default profiles: "
+ StringUtils.arrayToCommaDelimitedString(defaultProfiles));
}
else {
log.info("The following profiles are active: "
+ StringUtils.arrayToCommaDelimitedString(activeProfiles));
}
}
}
其实就相当于控制台输出如下日志:
No active profile set, falling back to default profiles: default
2.7、添加特定于引导的单例bean
此段代码所在类的具体路径:org.springframework.boot.SpringApplication
// 获取beanFactory,此处是(DefaultListableBeanFactory) 添加特定于引导的单例bean
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
// 注册一个单例bean,bean名称是springApplicationArguments
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
// 如果printedBanner 不为空,注册成单例bean,bean名称是springBootBanner
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
// 判断是否为AbstractAutowireCapableBeanFactory的实例
if (beanFactory instanceof AbstractAutowireCapableBeanFactory) {
// 是就设置是否允许bean定义重写,此处的allowBeanDefinitionOverriding 默认为false
// 需要注意的是DefaultListableBeanFactory里的allowBeanDefinitionOverriding 默认是true
((AbstractAutowireCapableBeanFactory) beanFactory).setAllowCircularReferences(this.allowCircularReferences);
// 判断是否为DefaultListableBeanFactory的实例
if (beanFactory instanceof DefaultListableBeanFactory) {
// 设置允许重新注册具有相同名称的不同定义
((DefaultListableBeanFactory) beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
}
// 默认是false
if (this.lazyInitialization) {
// 懒加载beanFactory 后置处理
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
这段代码的主要作用:
- 获取beanFactory,此处是(DefaultListableBeanFactory)
- 注册一个单例bean,bean名称是springApplicationArguments
- 如果printedBanner 不为空,也就是我们配置Banner相关的打印,则注册成单例bean,bean名称是springBootBanner
- 如果beanFactory 是AbstractAutowireCapableBeanFactory的实例,设置允许bean定义重写
- 如果beanFactory 是AbstractAutowireCapableBeanFactory的实例,并且也是DefaultListableBeanFactory的实例,则不允许重新注册具有相同名称的不同定义(默认是允许的,此处是要对主类操作,故不允许)
- 如果lazyInitialization为true,则添加懒加载beanFactory后置处理器LazyInitializationBeanFactoryPostProcessor,lazyInitialization默认是false
2.8、加载主类
2.8.1、加载资源
此方法所在类的具体路径:org.springframework.boot.SpringApplication
private Set<Class<?>> primarySources;
private Set<String> sources = new LinkedHashSet<>();
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);
}
primarySources是 SpringApplication 对象创建时赋值的,sources是环境准备是通过调用bindToSpringApplication设置的,主要是获取了spring.main.sources的值(如果配置了),我接下来看下load方法。
2.8.2、bean定义加载器
方法所在类的具体路径:org.springframework.boot.SpringApplication
protected void load(ApplicationContext context, Object[] sources) {
// 默认为false
if (logger.isDebugEnabled()) {
logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
}
// 创建一个BeanDefinitionLoader
BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);
// beanNameGenerator 默认为null
if (this.beanNameGenerator != null) {
loader.setBeanNameGenerator(this.beanNameGenerator);
}
// resourceLoader 默认为null
if (this.resourceLoader != null) {
loader.setResourceLoader(this.resourceLoader);
}
// environment 默认为null
if (this.environment != null) {
loader.setEnvironment(this.environment);
}
// 调用BeanDefinitionLoader 的load方法
loader.load();
}
protected BeanDefinitionLoader createBeanDefinitionLoader(BeanDefinitionRegistry registry, Object[] sources) {
// 实例化BeanDefinitionLoader
return new BeanDefinitionLoader(registry, sources);
}
此方法所在类的具体路径:org.springframework.boot.BeanDefinitionLoader
class BeanDefinitionLoader {
private final Object[] sources;
private final AnnotatedBeanDefinitionReader annotatedReader;
private final AbstractBeanDefinitionReader xmlReader;
private final BeanDefinitionReader groovyReader;
private final ClassPathBeanDefinitionScanner scanner;
protected BeanDefinitionLoader createBeanDefinitionLoader(BeanDefinitionRegistry registry, Object[] sources) {
return new BeanDefinitionLoader(registry, sources);
}
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 = (XML_ENABLED ? new XmlBeanDefinitionReader(registry) : null);
this.groovyReader = (isGroovyPresent() ? new GroovyBeanDefinitionReader(registry) : null);
this.scanner = new ClassPathBeanDefinitionScanner(registry);
this.scanner.addExcludeFilter(new ClassExcludeFilter(sources));
}
}
- 初始化注解形式的bean定义读取器AnnotatedBeanDefinitionReader
- 初始化xml格式的bean定义读取器XmlBeanDefinitionReader
- 初始化Groovy形式的bean定义读取器GroovyBeanDefinitionReader
- 初始化类路径bean定义扫描器ClassPathBeanDefinitionScanner
这时BeanDefinitionLoader就可以对类路径下不同形式的bean进行读取了。
2.8.3、bean定义加载器的load方法
此方法所在类的具体路径:org.springframework.boot.SpringApplication
class BeanDefinitionLoader {
void load() {
// 遍历sources,实例化时已经把参数赋值了
for (Object source : this.sources) {
load(source);
}
}
private void load(Object source) {
Assert.notNull(source, "Source must not be null");
// 如果是Class的实例
if (source instanceof Class<?>) {
load((Class<?>) source);
return;
}
// 如果是Resource的实例
if (source instanceof Resource) {
load((Resource) source);
return;
}
// 如果是Package的实例
if (source instanceof Package) {
load((Package) source);
return;
}
// 如果是CharSequence的实例
if (source instanceof CharSequence) {
load((CharSequence) source);
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)) {
// 通过注解bean定义读取器注册
this.annotatedReader.register(source);
}
}
private boolean isEligible(Class<?> type) {
// 不是匿名类,不是Groovy闭包,有构造函数
return !(type.isAnonymousClass() || isGroovyClosure(type) || hasNoConstructors(type));
}
}
- 遍历sources调用load(source)方法
- load(source)方法source根据类型进行加载,主类是Class
- 交给通过注解bean定义读取器AnnotatedBeanDefinitionReader去注册
2.8.4、注解bean定义读取器
此类的具体路径:org.springframework.context.annotation.AnnotatedBeanDefinitionReader
public class AnnotatedBeanDefinitionReader {
// 第一步
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
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
// 判断是否跳过,比如有存在@Condition注解条件判断
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
}
// 此处为null
abd.setInstanceSupplier(supplier);
// 解析scope元数据,解析是否配置了@Scope
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
// 设置Scope值,默认是singleton
abd.setScope(scopeMetadata.getScopeName());
// 获得beanName
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
// 通用注解做处理,目前有@Lazy、@Primary、@DependsOn、@Role、@Description
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
// 此处qualifiers 为null
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));
}
}
}
// 此处customizers 为null
if (customizers != null) {
for (BeanDefinitionCustomizer customizer : customizers) {
customizer.customize(abd);
}
}
// 实例化BeanDefinitionHolder
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
// 应用Scoped代理模式获取definitionHolder
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
// 注册bean定义
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}
}
这里我们主要讲下第三步的过程:
- 实例化AnnotatedGenericBeanDefinition,通过StandardAnnotationMetadata创建AnnotationMetadata,元数据搜索策略为SearchStrategy.INHERITED_ANNOTATIONS(搜索直接声明的注解和超类的注解),
- 通过条件评估ConditionEvaluator(创建应用上下文初始化的)判断该元注解是否需要跳过,比如比如有存在@Condition注解就会跳过
class ConditionEvaluator {
private final ConditionContextImpl context;
// 实例化AnnotatedBeanDefinitionReader时触发的
public ConditionEvaluator(@Nullable BeanDefinitionRegistry registry,
@Nullable Environment environment, @Nullable ResourceLoader resourceLoader) {
this.context = new ConditionContextImpl(registry, environment, resourceLoader);
}
// 第一步
public boolean shouldSkip(AnnotatedTypeMetadata metadata) {
return shouldSkip(metadata, null);
}
// 第二步
public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
// 判断元数据是否有@Conditional注解
if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
// 没有就跳过
return false;
}
// 判断配置阶段
if (phase == null) {
// 如果是AnnotationMetadata 的实例,并且是@Component、@ComponentScan、@Import、@ImportResource、@Bean任意一个则继续递归,为配置阶段
if (metadata instanceof AnnotationMetadata &&
ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {
return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);
}
// 如果不是AnnotationMetadata 的实例或者是一个接口,为注册阶段
return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);
}
List<Condition> conditions = new ArrayList<>();
// 遍历@Conditional的value属性值
for (String[] conditionClasses : getConditionClasses(metadata)) {
for (String conditionClass : conditionClasses) {
// 转换成Condition对象
Condition condition = getCondition(conditionClass, this.context.getClassLoader());
conditions.add(condition);
}
}
// 按照order排序
AnnotationAwareOrderComparator.sort(conditions);
for (Condition condition : conditions) {
ConfigurationPhase requiredPhase = null;
if (condition instanceof ConfigurationCondition) {
requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
}
// 如果Condition条件不匹配,则需要跳过
if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) {
return true;
}
}
return false;
}
- 解析Scope元数据,并设置Scope值,也就是去解析是否有@Scope注解
public class AnnotationScopeMetadataResolver implements ScopeMetadataResolver {
private final ScopedProxyMode defaultProxyMode;
protected Class<? extends Annotation> scopeAnnotationType = Scope.class;
public AnnotationScopeMetadataResolver() {
this.defaultProxyMode = ScopedProxyMode.NO;
}
@Override
public ScopeMetadata resolveScopeMetadata(BeanDefinition definition) {
ScopeMetadata metadata = new ScopeMetadata();
// 如果是AnnotatedBeanDefinition的实例
if (definition instanceof AnnotatedBeanDefinition) {
AnnotatedBeanDefinition annDef = (AnnotatedBeanDefinition) definition;
// 获取@Scope注解
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(
annDef.getMetadata(), this.scopeAnnotationType);
if (attributes != null) {
// 注解不为空,获取它的value,并设置scopeName
metadata.setScopeName(attributes.getString("value"));
// 获取作用域代理模式,默认是ScopedProxyMode.NO
ScopedProxyMode proxyMode = attributes.getEnum("proxyMode");
if (proxyMode == ScopedProxyMode.DEFAULT) {
proxyMode = this.defaultProxyMode;
}
metadata.setScopedProxyMode(proxyMode);
}
}
return metadata;
}
}
- 获取beanName,一个是通过注解获得名字,否则就是使用默认的规则类名的首字母小写
@Override
public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
// 如果是AnnotatedBeanDefinition的实例
if (definition instanceof AnnotatedBeanDefinition) {
// 从注解去获取beanName
String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);
if (StringUtils.hasText(beanName)) {
// Explicit bean name found.
return beanName;
}
}
// 默认beanName处理,类名的首字母小写作为beanName
return buildDefaultBeanName(definition, registry);
}
- 通用注解做处理,目前有@Lazy、@Primary、@DependsOn、@Role、@Description
public static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd) {
processCommonDefinitionAnnotations(abd, abd.getMetadata());
}
static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {
// @Lazy处理
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"));
}
}
// @Primary处理
if (metadata.isAnnotated(Primary.class.getName())) {
abd.setPrimary(true);
}
// @DependsOn处理
AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class);
if (dependsOn != null) {
abd.setDependsOn(dependsOn.getStringArray("value"));
}
// @Role处理
AnnotationAttributes role = attributesFor(metadata, Role.class);
if (role != null) {
abd.setRole(role.getNumber("value").intValue());
}
// @Descriptio处理
AnnotationAttributes description = attributesFor(metadata, Description.class);
if (description != null) {
abd.setDescription(description.getString("value"));
}
}
- 实例化BeanDefinitionHolder,并应用Scoped代理模式对definitionHolder 进行处理,如果没有配置@Scope,则默认的代理模式为ScopedProxyMode.NO,直接返回definitionHolder;如果配置了就会使用ScopedProxyMode.TARGET_CLASS(CGLIB代理)或者ScopedProxyMode.INTERFACES(JDK动态代理)
static BeanDefinitionHolder applyScopedProxyMode(
ScopeMetadata metadata, BeanDefinitionHolder definition, BeanDefinitionRegistry registry) {
// 获取作用域代理模式,默认是ScopedProxyMode.NO
ScopedProxyMode scopedProxyMode = metadata.getScopedProxyMode();
if (scopedProxyMode.equals(ScopedProxyMode.NO)) {
return definition;
}
// 判断是否是ScopedProxyMode.TARGET_CLASS,也就是cglib代理
boolean proxyTargetClass = scopedProxyMode.equals(ScopedProxyMode.TARGET_CLASS);
// 创建作用域代理模式,如果不是cglib代理,则使用jdk动态代理
return ScopedProxyCreator.createScopedProxy(definition, registry, proxyTargetClass);
}
- 注册主类的beanDefinition
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
// 在主名称下注册bean定义
String beanName = definitionHolder.getBeanName();
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// 为bean名称注册别名(如果有)
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
2.9、发布应用上下文准备完毕的事件
说到这里,实际上只要看我之前文章,应该对流程会非常的熟悉。不管总样,我们再简单过一下流程。
2.9.1、遍历运行监听器
此方法所在类的具体路径:org.springframework.boot.SpringApplicationRunListeners
class SpringApplicationRunListeners {
private final List<SpringApplicationRunListener> listeners;
void contextLoaded(ConfigurableApplicationContext context) {
doWithListeners("spring.boot.application.context-loaded", (listener) -> listener.contextLoaded(context));
}
private void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction) {
doWithListeners(stepName, listenerAction, null);
}
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();
}
}
之前的文章就知道了,这里的运行监听器就一个,那就是EventPublishingRunListener,接下里就是去看看事件发布运行监听器的上下文加载事件做了什么。
2.9.2、事件发布运行监听器
此方法所在类的具体路径:org.springframework.boot.context.event.EventPublishingRunListener
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
private final SimpleApplicationEventMulticaster initialMulticaster;
@Override
public void contextLoaded(ConfigurableApplicationContext context) {
for (ApplicationListener<?> listener : this.application.getListeners()) {
if (listener instanceof ApplicationContextAware) {
((ApplicationContextAware) listener).setApplicationContext(context);
}
context.addApplicationListener(listener);
}
// 实例化ApplicationPreparedEvent
// 交给事件广播器处理
this.initialMulticaster.multicastEvent(new ApplicationPreparedEvent(this.application, this.args, context));
}
}
- 实例化ApplicationPreparedEvent
- 通过事件广播器发布事件
准备应用上下文之前的方法applyInitializers已经加载了3个监听器(参考本文章节:2.4、应用所有初始化器),原本通过Spring工厂加载的结果是8个(参考:Alian解读SpringBoot 2.6.0 源码(一):SpringApplication对象创建(Spring工厂加载机制)),最终应用上下文里的监听器如下(不是指SpringApplication里的监听器,SpringApplication它还是8个):
- RSocketPortInfoApplicationContextInitializer的静态内部类Listener(准备应用上下文添加的)
- ServerPortInfoApplicationContextInitializer(准备应用上下文添加的)
- ConditionEvaluationReportLoggingListener的静态内部类ConditionEvaluationReportListener(准备应用上下文添加的)
- EnvironmentPostProcessorApplicationListener(应用上下文加载事件添加的)
- AnsiOutputApplicationListener(应用上下文加载事件添加的)
- LoggingApplicationListener(应用上下文加载事件添加的)
- BackgroundPreinitializer(应用上下文加载事件添加的)
- DelegatingApplicationListener(应用上下文加载事件添加的)
- ParentContextCloserApplicationListener(应用上下文加载事件添加的)
- ClearCachesApplicationListener(应用上下文加载事件添加的)
- FileEncodingApplicationListener(应用上下文加载事件添加的)
2.9.3、事件广播器
此方法所在类的具体路径:org.springframework.context.event.SimpleApplicationEventMulticaster
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
@Override
public void multicastEvent(ApplicationEvent event) {
// 通过事件解析事件类型
// 广播事件
multicastEvent(event, resolveDefaultEventType(event));
}
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
// executor默认为null
Executor executor = getTaskExecutor();
// 根据事件和事件类型获取监听器列表
// 然后遍历监听器列表,分别调用监听器的方法
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
} else {
// 调用
invokeListener(listener, event);
}
}
}
}
- 首先根据事件解析事件的类型(这里的事件是ApplicationPreparedEvent)
- 根据事件和事件类型进行事件广播
- 根据事件和事件类型获取事件监听器列表
2.9.4、获取符合事件的监听器
这里调用getApplicationListeners(event, type)方法,实际就是调用抽象类AbstractApplicationEventMulticaster中的getApplicationListeners方法,最终匹配到的监听器结果:
- EnvironmentPostProcessorApplicationListener
- LoggingApplicationListener
- BackgroundPreinitializer
- DelegatingApplicationListener
也符合我们下面这个对照表:
| 监听器 | 对应的事件 |
|---|---|
| AnsiOutputApplicationListener | ApplicationEnvironmentPreparedEvent |
| BackgroundPreinitializer | SpringApplicationEvent |
| ClearCachesApplicationListener | ContextRefreshedEvent |
| DelegatingApplicationListener | ApplicationEvent |
| EnvironmentPostProcessorApplicationListener | ApplicationEnvironmentPreparedEvent、ApplicationPreparedEvent、ApplicationFailedEvent |
| FileEncodingApplicationListener | ApplicationEnvironmentPreparedEvent |
| LoggingApplicationListener | ApplicationStartingEvent、ApplicationEnvironmentPreparedEvent、ApplicationPreparedEvent、 ContextClosedEvent、ApplicationFailedEvent |
| ParentContextCloserApplicationListener | ParentContextAvailableEvent |
具体的原因说过很多次了就不多说了,可以查阅我之前的文章:Alian解读SpringBoot 2.6.0 源码(二):启动流程分析之监听器解析
| 监听器 | 本次处理 |
|---|---|
| EnvironmentPostProcessorApplicationListener | 将所有延迟日志切换到其提供的目标 |
| LoggingApplicationListener | 注册日志系统LogbackLoggingSystem和日志组LoggerGroups |
| BackgroundPreinitializer | 什么都没有做 |
| DelegatingApplicationListener | 什么都没有做 |
结语
本章节主要是讲解准备应用上下文,其中发布了两个事件:应用上下文准备和应用上下文准备完毕,后续就是非常重要的应用上下文的刷新,这章的内容会很多,我们非多个章节进行解读,期待你的关注。
SpringBoot应用上下文准备
本文详细解析SpringBoot启动过程中的应用上下文准备阶段,包括环境设置、后置处理、初始化器的应用等关键步骤。
6571

被折叠的 条评论
为什么被折叠?



