-
前言
上文已經(jīng)創(chuàng)建了上下文對(duì)象匆篓,并初始化了bean的工廠類,加載了對(duì)部分注解的支持類惧互。
本文將在此基礎(chǔ)上繼續(xù)介紹上下文對(duì)象的進(jìn)一步信息完善鳍刷。文章基于springboot2.3.x系列的源碼(大部分以jar包中的源碼為例講解)鱼的,github的源碼與實(shí)際發(fā)版的可能略微不同理盆,不過(guò)整體流程差別不大。
本人第一次寫文章鸳吸,如有錯(cuò)誤或誤導(dǎo)歡迎留言指正熏挎。文章整體可能比較啰嗦,盡可能的將流程中的每一個(gè)重要的方法都講到晌砾。
1. prepareContext
源碼:
```
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
//注入環(huán)境屬性
context.setEnvironment(environment);
//上下文后置處理
this.postProcessApplicationContext(context);
//完善初始化類的屬性
this.applyInitializers(context);
//發(fā)送監(jiān)聽事件
listeners.contextPrepared(context);
//日志
if (this.logStartupInfo) {
this.logStartupInfo(context.getParent() == null);
this.logStartupProfileInfo(context);
}
//注冊(cè)傳入的配置參數(shù)為bean坎拐,這里將傳入的參數(shù)封裝成applicationArguments,內(nèi)部類似命令行
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
//banner打印
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
//這里默認(rèn)情況下bean定義不允許重復(fù)
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory)beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
//默認(rèn)不開啟延遲加載
if (this.lazyInitialization) {
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
//獲取全部的資源
//這里獲取了啟動(dòng)類的資源和 當(dāng)前SpringApplication中的source資源养匈。
//到目前來(lái)說(shuō)實(shí)際上只有啟動(dòng)類資源
Set<Object> sources = this.getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
this.load(context, sources.toArray(new Object[0]));
listeners.contextLoaded(context);
}
```
老樣子進(jìn)行逐個(gè)分析哼勇。但看這個(gè)方法并不復(fù)雜,整體上對(duì)上下文和工廠類進(jìn)行配置的完善呕乎。
1.1 postProcessApplicationContext 方法
源碼:
protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
// 是否自定義bean名稱生成類
if (this.beanNameGenerator != null) {
context.getBeanFactory().registerSingleton("org.springframework.context.annotation.internalConfigurationBeanNameGenerator", 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());
}
}
//是否添加數(shù)據(jù)轉(zhuǎn)換器
//在初始化環(huán)境對(duì)象的時(shí)候也有用到积担,這里可以直接通過(guò) context.getEnvironment().getConversionService()獲取到
if (this.addConversionService) {
context.getBeanFactory().setConversionService(ApplicationConversionService.getSharedInstance());
}
}
1.2 applyInitializers
完善與ApplicationContextInitializer接口相關(guān)的對(duì)象屬性,同時(shí)也可以對(duì)上下文屬性進(jìn)行配置猬仁。這些對(duì)象在this.initializers中,早在SpringApplication初始化的時(shí)候就已經(jīng)加載帝璧。通過(guò)已經(jīng)初始化好的上下文對(duì)相關(guān)類進(jìn)行完善。調(diào)用接口的initialize方法湿刽。
1.3 load
源碼:
protected void load(ApplicationContext context, Object[] sources) {
if (logger.isDebugEnabled()) {
logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
}
//構(gòu)建一個(gè)bean定義的加載器
BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);
if (this.beanNameGenerator != null) {
loader.setBeanNameGenerator(this.beanNameGenerator);
}
if (this.resourceLoader != null) {
loader.setResourceLoader(this.resourceLoader);
}
if (this.environment != null) {
loader.setEnvironment(this.environment);
}
//將資源加載成bean
loader.load();
}
void load() {
for (Object source : this.sources) {
load(source);
}
}
//按資源類型分別進(jìn)行加載的烁,
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());
}
主要加載了SpringApplication內(nèi)初始化的資源,包括我們的啟動(dòng)類xxApplication將會(huì)被注冊(cè)成bean诈闺。
小結(jié)
繼上下文創(chuàng)建完成后渴庆,又對(duì)其進(jìn)行了一些屬性的初始化,并加載了一些配置資源雅镊。