SpringBoot 2.6.4。2022-1024-keep heart
在应用启动过程中涉及到多个事件,通过EventPublishingRunListener来触发他们,同时又调用了ApplicationContextInitializer接口完成一些特定操作
开始启动-> 准备环境 -> 准备上下文 -> 刷新上下文 -> 后置处理
public ConfigurableApplicationContext run(String... args) {
long startTime = System.nanoTime();
DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();
ConfigurableApplicationContext context = null;
this.configureHeadlessProperty();
// 1. 获取所有的SpringApplicationRunListener接口实例 (SpringApplicationRunListener接口被EventPublishingRunListener实现)
SpringApplicationRunListeners listeners = this.getRunListeners(args);
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
// 创建 ApplicationArguments 对象 初始化默认应用参数类
// args是启动Spring应用的命令行参数,该参数可以在Spring应用中被访问。如:--server.port=9000
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 2. 项目运行环境Environment的预配置
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
this.configureIgnoreBeanInfo(environment);
// 准备Banner打印器
Banner printedBanner = this.printBanner(environment);
// 3. 创建Spring容器
context = this.createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
// 4. Spring容器前置处理
// 这一步主要是在容器刷新之前的准备动作。包含一个非常关键的操作:将启动类注入容器,为后续开启自动化配置奠定基础。
this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
// 5. 刷新容器
this.refreshContext(context);
// 6. Spring容器后置处理
this.afterRefresh(context, applicationArguments);
Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
if (this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), timeTakenToStartup);
}
// 7. 发出结束执行的事件通知
listeners.started(context, timeTakenToStartup);
// 8. 执行Runners
this.callRunners(context, applicationArguments);
} catch (Throwable var12) {
this.handleRunFailure(context, var12, listeners);
throw new IllegalStateException(var12);
}
try {
Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
listeners.ready(context, timeTakenToReady);
return context;
} catch (Throwable var11) {
this.handleRunFailure(context, var11, (SpringApplicationRunListeners)null);
throw new IllegalStateException(var11);
}
}
1. 注册监听器
SpringApplicationRunListeners listeners = this.getRunListeners(args);
解析getRunListeners
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class[]{SpringApplication.class, String[].class};
return new SpringApplicationRunListeners(logger, this.getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args), this.applicationStartup);
}
分析SpringApplicationRunListeners构造函数,包含3个参数,将SpringApplicationRunListener接口进行包装
class SpringApplicationRunListeners {
private final Log log;
private final List<SpringApplicationRunListener> listeners;
private final ApplicationStartup applicationStartup;
SpringApplicationRunListeners(Log log, Collection<? extends SpringApplicationRunListener> listeners, ApplicationStartup applicationStartup) {
this.log = log;
this.listeners = new ArrayList(listeners);
this.applicationStartup = applicationStartup;
}
// ...
}
实际包装的SpringApplicationRunListener接口
public interface SpringApplicationRunListener {
default void starting(ConfigurableBootstrapContext bootstrapContext) {
}
default void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {
}
default void contextPrepared(ConfigurableApplicationContext context) {
}
default void contextLoaded(ConfigurableApplicationContext context) {
}
default void started(ConfigurableApplicationContext context, Duration timeTaken) {
this.started(context);
}
/** @deprecated */
@Deprecated
default void started(ConfigurableApplicationContext context) {
}
default void ready(ConfigurableApplicationContext context, Duration timeTaken) {
this.running(context);
}
/** @deprecated */
@Deprecated
default void running(ConfigurableApplicationContext context) {
}
default void failed(ConfigurableApplicationContext context, Throwable exception) {
}
}
主要分析SpringApplicationRunListener接口的starting()方法,由EventPublishingRunListener实现
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
private final SpringApplication application;
private final String[] args;
private final SimpleApplicationEventMulticaster initialMulticaster;
// 构造函数
public EventPublishingRunListener(SpringApplication application, String[] args) {
this.application = application;
this.args = args;
this.initialMulticaster = new SimpleApplicationEventMulticaster();
Iterator var3 = application.getListeners().iterator();
while(var3.hasNext()) {
ApplicationListener<?> listener = (ApplicationListener)var3.next();
this.initialMulticaster.addApplicationListener(listener);
}
}
public void starting(ConfigurableBootstrapContext bootstrapContext) {
this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(bootstrapContext, this.application, this.args));
}
}
什么是initialMulticaster?分析构造函数可知,initialMulticaster即是SimpleApplicationEventMulticaster,并且将SpringApplication中的Listener都addApplicationListener()添加进去
什么是multicastEvent()?在其中传入new ApplicationStartingEvent(bootstrapContext, this.application, this.args)。分析multicastEvent()源码,每一个类型的处理方法都会传入一个指定的事件
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = eventType != null ? eventType : this.resolveDefaultEventType(event);
Executor executor = this.getTaskExecutor();
// 1.迭代器获取所有的监听器
Iterator var5 = this.getApplicationListeners(event, type).iterator();
while(var5.hasNext()) {
ApplicationListener<?> listener = (ApplicationListener)var5.next();
if (executor != null) {
executor.execute(() -> {
// 2.调用监听器
this.invokeListener(listener, event);
});
} else {
this.invokeListener(listener, event);
}
}
}
可以看出在处理事件的方法内部做了两件事(multicastEvent方法内部标红的方法调用):
- 获取所有的监听器
- 调用监听器
// 获取所有的监听器
protected Collection<ApplicationListener<?>> getApplicationListeners(ApplicationEvent event, ResolvableType eventType) {
Object source = event.getSource();
Class<?> sourceType = source != null ? source.getClass() : null;
AbstractApplicationEventMulticaster.ListenerCacheKey cacheKey = new AbstractApplicationEventMulticaster.ListenerCacheKey(eventType, sourceType);
AbstractApplicationEventMulticaster.CachedListenerRetriever newRetriever = null;
AbstractApplicationEventMulticaster.CachedListenerRetriever existingRetriever = (AbstractApplicationEventMulticaster.CachedListenerRetriever)this.retrieverCache.get(cacheKey);
if (existingRetriever == null && (this.beanClassLoader == null || ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) && (sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
newRetriever = new AbstractApplicationEventMulticaster.CachedListenerRetriever();
existingRetriever = (AbstractApplicationEventMulticaster.CachedListenerRetriever)this.retrieverCache.putIfAbsent(cacheKey, newRetriever);
if (existingRetriever != null) {
newRetriever = null;
}
}
if (existingRetriever != null) {
Collection<ApplicationListener<?>> result = existingRetriever.getApplicationListeners();
if (result != null) {
return result;
}
}
// 实际获取逻辑
return this.retrieveApplicationListeners(eventType, sourceType, newRetriever);
}
// 循环判断监听器声明的事件类型是否和本次处理的事件类型相同,本次处理的类型为ApplicationStartingEvent,不符合事件类型的事件会被排除,只调用声明了此类型的监听器。
private Collection<ApplicationListener<?>> retrieveApplicationListeners(ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable AbstractApplicationEventMulticaster.CachedListenerRetriever retriever) {
List<ApplicationListener<?>> allListeners = new ArrayList();
Set<ApplicationListener<?>> filteredListeners = retriever != null ? new LinkedHashSet() : null;
Set<String> filteredListenerBeans = retriever != null ? new LinkedHashSet() : null;
LinkedHashSet listeners;
LinkedHashSet listenerBeans;
synchronized(this.defaultRetriever) {
listeners = new LinkedHashSet(this.defaultRetriever.applicationListeners);
listenerBeans = new LinkedHashSet(this.defaultRetriever.applicationListenerBeans);
}
Iterator var9 = listeners.iterator();
// 循环判断
while(var9.hasNext()) {
ApplicationListener<?> listener = (ApplicationListener)var9.next();
if (this.supportsEvent(listener, eventType, sourceType)) {
if (retriever != null) {
filteredListeners.add(listener);
}
allListeners.add(listener);
}
}
while(var16.hasNext()) {
String listenerBeanName = (String)var16.next();
try {
// 循环判断所有的监听器(ApplicationListener)判断其是否支持当前所处理的事件(ApplicationStartingEvent)
if (this.supportsEvent(beanFactory, listenerBeanName, eventType)) {
// ...
}
}
}
// ...
return allListeners;
}
深钻supportsEvent(beanFactory, listenerBeanName, eventType)
// 在判断当前监听器是否支持指定事件之前,将当前监听器转换为了GenericApplicationListener
protected boolean supportsEvent(ApplicationListener<?> listener, ResolvableType eventType, @Nullable Class<?> sourceType) {
GenericApplicationListener smartListener = listener instanceof GenericApplicationListener ? (GenericApplicationListener)listener : new GenericApplicationListenerAdapter(listener);
// 使用GenericApplicationListener的supportsEventType()方法
return ((GenericApplicationListener)smartListener).supportsEventType(eventType) && ((GenericApplicationListener)smartListener).supportsSourceType(sourceType);
}
分析上述代码如果Listener是GenericApplicationListener,那更好直接赋值;否则就new一个GenericApplicationListenerAdapter并将当前listener丢进去,继续深钻GenericApplicationListenerAdapter做了些什么?
private static final Map<Class<?>, ResolvableType> eventTypeCache = new ConcurrentReferenceHashMap();
private final ApplicationListener<ApplicationEvent> delegate;
@Nullable
private final ResolvableType declaredEventType;
// GenericApplicationListenerAdapter构造函数
public GenericApplicationListenerAdapter(ApplicationListener<?> delegate) {
Assert.notNull(delegate, "Delegate listener must not be null");
this.delegate = delegate;
this.declaredEventType = resolveDeclaredEventType(this.delegate);
}
分析GenericApplicationListenerAdapter的构造函数可知获取了监听器声明的事件类型,即resolveDeclaredEventType(this.delegate)
@Nullable
private static ResolvableType resolveDeclaredEventType(ApplicationListener<ApplicationEvent> listener) {
ResolvableType declaredEventType = resolveDeclaredEventType(listener.getClass());
if (declaredEventType == null || declaredEventType.isAssignableFrom(ApplicationEvent.class)) {
Class<?> targetClass = AopUtils.getTargetClass(listener);
if (targetClass != listener.getClass()) {
declaredEventType = resolveDeclaredEventType(targetClass);
}
}
return declaredEventType;
}
比较了当前处理的事件和监听器处理的事件是否相符
public boolean supportsEventType(ResolvableType eventType) {
if (this.delegate instanceof GenericApplicationListener) {
return ((GenericApplicationListener)this.delegate).supportsEventType(eventType);
} else if (this.delegate instanceof SmartApplicationListener) {
Class<? extends ApplicationEvent> eventClass = eventType.resolve();
return eventClass != null && ((SmartApplicationListener)this.delegate).supportsEventType(eventClass);
} else {
return this.declaredEventType == null || this.declaredEventType.isAssignableFrom(eventType);
}
}
监听器列表
LoggingApplicationListener
BackgroundPreinitializer
DelegatingApplicationListener
LiquibaseServiceLocatorApplicationListener
最先执行的Starting事件我们可以得知SpringBoot是如何处理事件,以及事件的匹配是如何实现。后续的其他事件处理都是同样的方式。
在run方法的try catch代码块内部,开始处理有关上下文的一些流程。SpringBoot也设计了精简的流程来处理不同的任务,具体来说就是如下几个方法共同完成每个阶段的任务。
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
在准备环境和准备上下文的过程中都传入了监听器,意味着它们会被调用。
2. 环境准备阶段
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
// 1. 获取或者创建一个ConfigurableEnvironment
ConfigurableEnvironment environment = this.getOrCreateEnvironment();
// 2. 配置环境
this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());
// 3. 将ConfigurationPropertySource支持附加到指定的环境
ConfigurationPropertySources.attach((Environment)environment);
// 4. 触发环境信息准备完毕事件
listeners.environmentPrepared(bootstrapContext, (ConfigurableEnvironment)environment);
DefaultPropertiesPropertySource.moveToEnd((ConfigurableEnvironment)environment);
Assert.state(!((ConfigurableEnvironment)environment).containsProperty("spring.main.environment-prefix"), "Environment prefix cannot be set via properties.");
// 5. 绑定环境信息到当前应用程序
this.bindToSpringApplication((ConfigurableEnvironment)environment);
if (!this.isCustomEnvironment) {
environment = this.convertEnvironment((ConfigurableEnvironment)environment);
}
// 6. 重复了第3步操作
ConfigurationPropertySources.attach((Environment)environment);
return (ConfigurableEnvironment)environment;
}
此处有一个疑问,为什么第6步要重复一下第3步的操作?
-
- 深究ConfigurableEnvironment对象的创建过程:
private ConfigurableEnvironment getOrCreateEnvironment() {
if (this.environment != null) {
return this.environment;
} else {
switch(this.webApplicationType) {
case SERVLET:
return new ApplicationServletEnvironment();
case REACTIVE:
return new ApplicationReactiveWebEnvironment();
default:
return new ApplicationEnvironment();
}
}
}
若environment不为null则直接返回,否则根据webApplicationType来创建环境对象,比如此处我们的应用为SERVLET,return new ApplicationServletEnvironment();
class ApplicationServletEnvironment extends StandardServletEnvironment {
ApplicationServletEnvironment() {
}
protected String doGetActiveProfilesProperty() {
return null;
}
protected String doGetDefaultProfilesProperty() {
return null;
}
protected ConfigurablePropertyResolver createPropertyResolver(MutablePropertySources propertySources) {
return ConfigurationPropertySources.createPropertyResolver(propertySources);
}
}
继续下钻发现ApplicationServletEnvironment继承了StandardServletEnvironment
public class StandardServletEnvironment extends StandardEnvironment implements ConfigurableWebEnvironment {
public static final String SERVLET_CONTEXT_PROPERTY_SOURCE_NAME = "servletContextInitParams";
public static final String SERVLET_CONFIG_PROPERTY_SOURCE_NAME = "servletConfigInitParams";
public static final String JNDI_PROPERTY_SOURCE_NAME = "jndiProperties";
private static final boolean jndiPresent = ClassUtils.isPresent("javax.naming.InitialContext", StandardServletEnvironment.class.getClassLoader());
public StandardServletEnvironment() {
}
protected StandardServletEnvironment(MutablePropertySources propertySources) {
super(propertySources);
}
protected void customizePropertySources(MutablePropertySources propertySources) {
propertySources.addLast(new StubPropertySource("servletConfigInitParams"));
propertySources.addLast(new StubPropertySource("servletContextInitParams"));
if (jndiPresent && JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable()) {
propertySources.addLast(new JndiPropertySource("jndiProperties"));
}
super.customizePropertySources(propertySources);
}
public void initPropertySources(@Nullable ServletContext servletContext, @Nullable ServletConfig servletConfig) {
WebApplicationContextUtils.initServletPropertySources(this.getPropertySources(), servletContext, servletConfig);
}
}
这里可以看到customizePropertySources(MutablePropertySources propertySources)方法中addLast了两个配置集,分别是servletConfigInitParams/servletContextInitParams,jndiProperties配置集视情况再增加。之后调用父类StandardEnvironment的方法super.customizePropertySources(propertySources);
public class StandardEnvironment extends AbstractEnvironment {
public static final String SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME = "systemEnvironment";
public static final String SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME = "systemProperties";
public StandardEnvironment() {
}
protected StandardEnvironment(MutablePropertySources propertySources) {
super(propertySources);
}
protected void customizePropertySources(MutablePropertySources propertySources) {
propertySources.addLast(new PropertiesPropertySource("systemProperties", this.getSystemProperties()));
propertySources.addLast(new SystemEnvironmentPropertySource("systemEnvironment", this.getSystemEnvironment()));
}
}
父类其中还是继续增加配置集,分别是系统级别的配置集systemProperties和systemEnvironment
至此一般就包括了4个配置集:
- servletConfigInitParams
- servletContextInitParams
- systemEnvironment
- systemProperties
环境信息就是profiles和配置文件以及系统环境信息的封装,在开发过程中我们根据官方指南和经验得知一个profile是有一套配置信息的,那么它的功能实现肯定是首先获取profile,然后再获取配置。但是我们在环境对象创建的时候发现它已经初始化了4个配置集,并且包含了系统配置(当前应用所运行的载体的配置信息)。但是这些配置信息除了系统配置之外其他都为空值,可以推断它只是预先初始化好配置容器,后续进行填充更新
问题来了:
- 配置什么时候被填充?
- 被填充的配置怎么来?
回到SpringApplication的run() -> prepareEnvironment()->configureEnvironment()方法
protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
// 1. 注册ConversationServoce,Spring内部用来处理统一类型转换的服务(将配置文件中的不同类型转换为它所要表示的类型例如:xxx.enable = false,将会将false转换为真正的boolean对象),一些常见的转换服务有StringToDurationConverter、DurationToStringConverter、StringToDataSizeConverter等
if (this.addConversionService) {
environment.setConversionService(new ApplicationConversionService());
}
// 2. 配置属性资源
this.configurePropertySources(environment, args);
// 3. 配置profiles
this.configureProfiles(environment, args);
}
深钻2. 配置属性资源this.configurePropertySources(environment, args);
protected void configurePropertySources(ConfigurableEnvironment environment, String[] args) {
// 1. 获取环境对象中的配置对象
MutablePropertySources sources = environment.getPropertySources();
// 2. 检查并插入默认配置
if (!CollectionUtils.isEmpty(this.defaultProperties)) {
DefaultPropertiesPropertySource.addOrMerge(this.defaultProperties, sources);
}
// 3. 检查并插入命令行配置
if (this.addCommandLineProperties && args.length > 0) {
String name = "commandLineArgs";
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));
}
}
}
深钻3. 配置profiles,this.configureProfiles(environment, args);
TODO:留一个坑,为什么可以预留一个空方法体,如何实现调用
// 啥都没有?
protected void configureProfiles(ConfigurableEnvironment environment, String[] args) {
}
- 初始化可变环境信息对象,初始化4个系统级别的配置集
- 将应用启动的参数信息填入环境信息对象
- 包装为SpringConfigurationPropertySources对象放入环境信息中
监听器触发ConfigDataEnvironmentPostProcessor
(从2.4.0开始弃用ConfigFileApplicationListener,改用ConfigDataEnvironmentPostProcessor)
在spring.factories中注册了该监听器:
org.springframework.boot.env.EnvironmentPostProcessor=\
org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor,\
public class ConfigDataEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered {}
ConfigDataEnvironmentPostProcessor实现了Ordered接口,意味着它具有排序能力(相同接口实现列表中的排序优先级),并且它的优先级被设置为了最高-10(Integer.MIN_VALUE为最高优先级,+10就相当于数值加大优先级减10):DEFAULT_ORDER = Ordered.HIGHEST_PRECEDENCE + 10。
// EnvironmentPostProcessorApplicationListener
@Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ApplicationEnvironmentPreparedEvent) {
onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent) event);
}
if (event instanceof ApplicationPreparedEvent) {
onApplicationPreparedEvent();
}
if (event instanceof ApplicationFailedEvent) {
onApplicationFailedEvent();
}
}
private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
ConfigurableEnvironment environment = event.getEnvironment();
SpringApplication application = event.getSpringApplication();
// 1. 遍历获取所有的EnvironmentPostProcessor
for (EnvironmentPostProcessor postProcessor : getEnvironmentPostProcessors(application.getResourceLoader(),
event.getBootstrapContext())) {
// 2.执行所有的Processor
postProcessor.postProcessEnvironment(environment, application);
}
}
默认情况下加载以下Processor(优先级从高到低):
- RandomValuePropertySourceEnvironmentPostProcessor
- SystemEnvironmentPropertySourceEnvironmentPostProcessor
- SpringApplicationJsonEnvironmentPostProcessor
- CloudFoundryVcapEnvironmentPostProcessor
- ConfigDataEnvironmentPostProcessor
- DebugAgentEnvironmentPostProcessor
- IntegrationPropertiesEnvironmentPostProcessor
TODO Processor分析
① 配置文件的加载动作是由监听器ConfigDataEnvironmentPostProcessor触发
② 根据指定的不同profile匹配指定的配置文件名称,默认支持的文件后缀为:properties/xml/yml/yaml;默认支持的配置文件路径有:classpath:/,classpath:/config/,file:./,file:./config/
③ 不同类型的文件有对应的解析器处理
④ 配置文件的优先级首先以profile的声明顺序为主,后声明的优先级高,文件类型以默认支持的文件类型顺序为主,最先声明的优先级最高
⑥ 指定profile可以通过参数spring.profiles.active=dev,common指定,也可以在配置文件中声明spring.profiles=dev,common来指定,不推荐使用后者
⑦ 指定配置文件的位置可以通过参数spring.config.location=xxxx来指定
⑧ 指定配置文件的名称可以通过参数spring.config.name=xxxx来指定
3. 准备上下文阶段
// 创建Spring容器
context = createApplicationContext();
// 预处理上下文容器
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
解析prepareContext()
// SpringApplication.java
private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
// 设置环境对象,传入解析完毕的profiles的对象,Context内部则是不完整的对象
context.setEnvironment(environment);
// *设置上下文参数
postProcessApplicationContext(context);
// *加载ApplicationContextInitializers
applyInitializers(context);
// 触发开始准备上下文事件
listeners.contextPrepared(context);
bootstrapContext.close(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
// 记录活动的profiles日志
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
// 将启动参数包装为名为springApplicationArguments的DefaultApplicationArguments对象,并以单例模式注册
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
// 设置打印的Banner
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
//设置是否允许覆盖BeanDefinition
if (beanFactory instanceof AbstractAutowireCapableBeanFactory) {
((AbstractAutowireCapableBeanFactory) beanFactory).setAllowCircularReferences(this.allowCircularReferences);
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
}
if (this.lazyInitialization) {
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
// 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);
}
深钻设置上下文参数postProcessApplicationContext(context);:
// SpringApplication.java
protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
// 以单例模式注册beanNameGenerator
if (this.beanNameGenerator != null) {
context.getBeanFactory().registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
this.beanNameGenerator);
}
// 为上下文设置资源加载器和类加载器
if (this.resourceLoader != null) {
if (context instanceof GenericApplicationContext) {
((GenericApplicationContext) context).setResourceLoader(this.resourceLoader);
}
if (context instanceof DefaultResourceLoader) {
((DefaultResourceLoader) context).setClassLoader(this.resourceLoader.getClassLoader());
}
}
// 为上下文设置转换服务
if (this.addConversionService) {
context.getBeanFactory().setConversionService(context.getEnvironment().getConversionService());
}
}
深钻加载ApplicationContextInitializers,applyInitializers(context);
protected void applyInitializers(ConfigurableApplicationContext context) {
// 调用每一个实现类的initialize方法
for (ApplicationContextInitializer initializer : getInitializers()) {
Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
ApplicationContextInitializer.class);
Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
// 初始化
initializer.initialize(context);
}
}
// 将之前获取到的集合进行排序并返回只读集合
public Set<ApplicationContextInitializer<?>> getInitializers() {
return asUnmodifiableOrderedSet(this.initializers);
}
// DelegatingApplicationContextInitializer.java
@Override
public void initialize(ConfigurableApplicationContext context) {
// 获取环境对象
ConfigurableEnvironment environment = context.getEnvironment();
// 获取context.initializer.classes属性指定的实现类
List<Class<?>> initializerClasses = getInitializerClasses(environment);
if (!initializerClasses.isEmpty()) {
// 调用initialize()方法
applyInitializerClasses(context, initializerClasses);
}
}
private List<Class<?>> getInitializerClasses(ConfigurableEnvironment env) {
// 通过指定属性去获取,此处常量属性值为context.initializer.classes
String classNames = env.getProperty(PROPERTY_NAME);
List<Class<?>> classes = new ArrayList<>();
if (StringUtils.hasLength(classNames)) {
for (String className : StringUtils.tokenizeToStringArray(classNames, ",")) {
// 根据代码可以推断出 context.initializer.classes的值可以用逗号拼接
classes.add(getInitializerClass(className));
}
}
return classes;
}
// SpringApplication.java
protected void logStartupProfileInfo(ConfigurableApplicationContext context) {
Log log = getApplicationLog();
if (log.isInfoEnabled()) {
List<String> activeProfiles = quoteProfiles(context.getEnvironment().getActiveProfiles());
if (ObjectUtils.isEmpty(activeProfiles)) {
List<String> defaultProfiles = quoteProfiles(context.getEnvironment().getDefaultProfiles());
String message = String.format("%s default %s: ", defaultProfiles.size(),
(defaultProfiles.size() <= 1) ? "profile" : "profiles");
log.info("No active profile set, falling back to " + message
+ StringUtils.collectionToDelimitedString(defaultProfiles, ", "));
}
else {
String message = (activeProfiles.size() == 1) ? "1 profile is active: "
: activeProfiles.size() + " profiles are active: ";
log.info("The following " + message + StringUtils.collectionToDelimitedString(activeProfiles, ", "));
}
}
}
将参数对象注册为单例模式
// SpringApplication.java#prepareContext()
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
是否允许覆盖Bean定义
// SpringApplication.java#prepareContext()
// spring.main.allow-bean-definition-overriding参数有关,默认情况下在DefaultListableBeanFactory中是true,但是SpringBoot在此处给设置成了false
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
加载bean到上下文中
// SpringApplication.java#prepareContext()
// Load the sources 获取当前应用要加载的资源
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
// *加载bean
load(context, sources.toArray(new Object[0]));
// SpringApplication.java#prepareContext()->load()
// 创建Bean加载器,并加载
protected void load(ApplicationContext context, Object[] sources) {
if (logger.isDebugEnabled()) {
logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
}
// 创建BeanDefinitionLoader
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();
}
初始化BeanDefinitionLoader:通过观察它的内部属性和构造方法可以看出,它支持加载基于编程方式配置的类,支持xml文件配置的类,支持groovy和xml混合定义的类的加载。它使用门面模式封装了这些具体的加载器。此处只需要先知道BeanDefinitionLoader用于加载Bean,且它内部封装了多个类读取器即可
不必深入。先了解大体的功能性即可。
// SpringApplication.java#prepareContext()->load()->createBeanDefinitionLoader()
protected BeanDefinitionLoader createBeanDefinitionLoader(BeanDefinitionRegistry registry, Object[] sources) {
return new BeanDefinitionLoader(registry, sources);
}
// 实体类
class BeanDefinitionLoader {
// Static final field to facilitate code removal by Graal
private static final boolean XML_ENABLED = !SpringProperties.getFlag("spring.xml.ignore");
private static final Pattern GROOVY_CLOSURE_PATTERN = Pattern.compile(".*\\$_.*closure.*");
// 类的来源
private final Object[] sources;
// JavaConfig类读取器
private final AnnotatedBeanDefinitionReader annotatedReader;
// xml文件类读取器
private final AbstractBeanDefinitionReader xmlReader;
private final BeanDefinitionReader groovyReader;
// classpath类读取器
private final ClassPathBeanDefinitionScanner scanner;
// 资源加载器
private ResourceLoader resourceLoader;
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));
}
// 省略...
}
使用BeanDefinitionLoader加载Bean
// BeanDefinitionLoader.java
// 统一加载方法
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<?>) {
load((Class<?>) source);
return;
}
if (source instanceof Resource) {
load((Resource) source);
return;
}
if (source instanceof Package) {
load((Package) source);
return;
}
if (source instanceof CharSequence) {
load((CharSequence) source);
return;
}
throw new IllegalArgumentException("Invalid source type " + source.getClass());
}
此处我们选择SpringBoot典型的资源加载方式Class方式来分析,在应用程序启动入口我们使用的是SpringApplication.run(Example.class, args);而Example.class是我们的main函数所在类,以它作为资源来加载。
// BeanDefinitionLoader.java load((Class<?>) source)
private void load(Class<?> source) {
// 判断是否支持Groovy
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)) {
// 读取@Component注解进行注册
this.annotatedReader.register(source);
}
}
private boolean isEligible(Class<?> type) {
return !(type.isAnonymousClass() || isGroovyClosure(type) || hasNoConstructors(type));
}
注册:
private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name, @Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier, @Nullable BeanDefinitionCustomizer[] customizers) {
// 1. 创建一个带注解元数据的类定义
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
// 2. 判断是否有@Conditional注解
if (!this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
// 3. 设置一个创建Bean的回调。基本都是空值
abd.setInstanceSupplier(supplier);
// 4. 获取当前Bean的作用域元数据,判断依据是是否包含@Scope注解。ScopeMetadata包含类的作用域描述(singleton | prototype)和代理模式描述ScopedProxyMode,默认为单例模式,不使用代理创建。
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
abd.setScope(scopeMetadata.getScopeName());
String beanName = name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry);
// 5. 处理常用注解,包括@Lazy、@Primary、@Role、@Description、@DependsOn,他们将被设置到BeanDefinition的属性当中。
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
int var10;
int var11;
// 6. 检查传入的Qualifiers
if (qualifiers != null) {
Class[] var9 = qualifiers;
var10 = qualifiers.length;
for(var11 = 0; var11 < var10; ++var11) {
Class<? extends Annotation> qualifier = var9[var11];
if (Primary.class == qualifier) {
abd.setPrimary(true);
} else if (Lazy.class == qualifier) {
abd.setLazyInit(true);
} else {
abd.addQualifier(new AutowireCandidateQualifier(qualifier));
}
}
}
if (customizers != null) {
BeanDefinitionCustomizer[] var13 = customizers;
var10 = customizers.length;
for(var11 = 0; var11 < var10; ++var11) {
BeanDefinitionCustomizer customizer = var13[var11];
customizer.customize(abd);
}
}
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}
}
发布ApplicationPreparedEvent事件,EventPublishingRunListener.contextLoaded(ConfigurableApplicationContext context)方法触发。
在真正触发事件之前,它处理了ApplicationContextAware实现,为其设置了上下文。为ApplicationContextAware扩展接口设置上下文
@Override
public void contextLoaded(ConfigurableApplicationContext context) {
for (ApplicationListener<?> listener : this.application.getListeners()) {
if (listener instanceof ApplicationContextAware) {
((ApplicationContextAware) listener).setApplicationContext(context);
}
// 将所有监听器赋值给上下文
context.addApplicationListener(listener);
}
this.initialMulticaster.multicastEvent(new ApplicationPreparedEvent(this.application, this.args, context));
}
ConfigFileApplicationListener
添加了一个BeanFactoryPostProcessor:PropertySourceOrderingPostProcessor,用于重排序defaultProperties
LoggingApplicationListener
以单例模式注册注册当前日志系统
总结:在预处理上下文时将先前加载的一些属性赋值给context,执行了ApplicationContextInitializers的实现类,为ApplicationContextAware接口填充context对象。
4. 刷新容器
5. 后置处理阶段
参考资料: