-
前言
上文已经创建了上下文对象,并初始化了bean的工厂类,加载了对部分注解的支持类。
本文将在此基础上继续介绍上下文对象的进一步信息完善。文章基于springboot2.3.x系列的源码(大部分以jar包中的源码为例讲解),github的源码与实际发版的可能略微不同,不过整体流程差别不大。 本人第一次写文章,如有错误或误导欢迎留言指正。文章整体可能比较啰嗦,尽可能的将流程中的每一个重要的方法都讲到。
1. prepareContext
源码:
```
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
//注入环境属性
context.setEnvironment(environment);
//上下文后置处理
this.postProcessApplicationContext(context);
//完善初始化类的属性
this.applyInitializers(context);
//发送监听事件
listeners.contextPrepared(context);
//日志
if (this.logStartupInfo) {
this.logStartupInfo(context.getParent() == null);
this.logStartupProfileInfo(context);
}
//注册传入的配置参数为bean,这里将传入的参数封装成applicationArguments,内部类似命令行
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
//banner打印
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
//这里默认情况下bean定义不允许重复
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory)beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
//默认不开启延迟加载
if (this.lazyInitialization) {
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
//获取全部的资源
//这里获取了启动类的资源和 当前SpringApplication中的source资源。
//到目前来说实际上只有启动类资源
Set<Object> sources = this.getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
this.load(context, sources.toArray(new Object[0]));
listeners.contextLoaded(context);
}
```
老样子进行逐个分析。但看这个方法并不复杂,整体上对上下文和工厂类进行配置的完善。
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());
}
}
//是否添加数据转换器
//在初始化环境对象的时候也有用到,这里可以直接通过 context.getEnvironment().getConversionService()获取到
if (this.addConversionService) {
context.getBeanFactory().setConversionService(ApplicationConversionService.getSharedInstance());
}
}
1.2 applyInitializers
完善与ApplicationContextInitializer接口相关的对象属性,同时也可以对上下文属性进行配置。这些对象在this.initializers中,早在SpringApplication初始化的时候就已经加载。通过已经初始化好的上下文对相关类进行完善。调用接口的initialize方法。
1.3 load
源码:
protected void load(ApplicationContext context, Object[] sources) {
if (logger.isDebugEnabled()) {
logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
}
//构建一个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);
}
}
//按资源类型分别进行加载,
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内初始化的资源,包括我们的启动类xxApplication将会被注册成bean。
小结
继上下文创建完成后,又对其进行了一些属性的初始化,并加载了一些配置资源。