这章我们开始学习SpringApplication对ApplicationContext的相关操作,ApplicationContext的prepare与refresh可以算是SpringApplication的最重要部分。
SpringApplication的prepareContext方法:
private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
context.setEnvironment(environment);
postProcessApplicationContext(context);
applyInitializers(context);
listeners.contextPrepared(context);
bootstrapContext.close(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
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);
}
由于我的应用引入了spring-boot-starter-webflux依赖,所以这里的context类型为AnnotationConfigReactiveWebServerApplicationContext,environment类型为ApplicationReactiveWebEnvironment。AnnotationConfigReactiveWebServerApplicationContext的setEnvironment方法源码:
public void setEnvironment(ConfigurableEnvironment environment) {
super.setEnvironment(environment);
this.reader.setEnvironment(environment);
this.scanner.setEnvironment(environment);
}
super.setEnvironment(environment)调用的是AbstractApplicationContext的setEnvironment方法:
public void setEnvironment(ConfigurableEnvironment environment) {
this.environment = environment;
}
AnnotationConfigReactiveWebServerApplicationContext的成员字段reader和scanner在构造方法被调用时进行赋值:
public AnnotationConfigReactiveWebServerApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
AnnotatedBeanDefinitionReader是方便的适配器,用于bean类的编程注册。其构造方法如下:
/**
* 为给定的注册表创建一个新的AnnotatedBeanDefinitionReader。
* 如果注册表是EnvironmentCapable,例如是ApplicationContext,则将继承Environment,否则将创建并使用新的StandardEnvironment。
* @param registry 以BeanDefinitionRegistry的形式将bean定义加载到其中的BeanFactory
*/
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
this(registry, getOrCreateEnvironment(registry));
}
/**
* 使用给定的Environment为给定的注册表创建一个新的AnnotatedBeanDefinitionReader 。
* @param registry 以BeanDefinitionRegistry的形式将bean定义加载到其中的BeanFactory
* @param environment 评估bean定义配置文件时使用的Environment 。
* @since 3.1
*/
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
Assert.notNull(environment, "Environment must not be null");
this.registry = registry;
this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
/**
* 如果可以,从给定的BeanDefinitionRegistry中获取环境,否则返回一个新的标准环境。
*/
private static Environment getOrCreateEnvironment(BeanDefinitionRegistry registry) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
if (registry instanceof EnvironmentCapable) {
return ((EnvironmentCapable) registry).getEnvironment();
}
return new StandardEnvironment();
}
ClassPathBeanDefinitionScanner是一个bean定义扫描器,它检测类路径上的候选bean,使用给定的注册表(BeanFactory或ApplicationContext)注册相应的bean定义。ClassPathBeanDefinitionScanner通过可配置的类型过滤器检测候选类,默认过滤器包括使用 Spring 的@Component 、 @Repository 、 @Service或@Controller原型注解的类。其构造方法的源码如下:
/**
* 为给定的bean工厂创建一个新的ClassPathBeanDefinitionScanner 。
* @param registry 以BeanDefinitionRegistry的形式将 bean 定义加载到其中的BeanFactory
*/
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) {
this(registry, true);
}
/**
* 为给定的 bean 工厂创建一个新的ClassPathBeanDefinitionScanner 。
* 如果传入的 bean factory 不仅实现了BeanDefinitionRegistry接口,还实现了ResourceLoader接口,那么它也会被用作默认的ResourceLoader 。
* 这通常是org.springframework.context.ApplicationContext实现的情况。
* 如果给定一个普通的BeanDefinitionRegistry ,默认的ResourceLoader将是一个org.springframework.core.io.support.PathMatchingResourcePatternResolver 。
* 如果传入的 bean 工厂也实现了EnvironmentCapable它的环境将被这个读者使用。否则,阅读器将初始化并使用StandardEnvironment 。
* 所有ApplicationContext实现都是EnvironmentCapable ,而普通的BeanFactory实现不是。
* @param registry 以BeanDefinitionRegistry的形式将 bean 定义加载到其中的BeanFactory
* @param useDefaultFilters 是否包含@Component 、 @Repository 、 @Service和@Controller原型注解的默认过滤器
*/
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters) {
this(registry, useDefaultFilters, getOrCreateEnvironment(registry));
}
/**
* 为给定的 bean 工厂创建一个新的ClassPathBeanDefinitionScanner ,并在评估 bean 定义配置文件元数据时使用给定的Environment 。
* 如果传入的 bean factory 不仅实现了BeanDefinitionRegistry接口,还实现了ResourceLoader接口,那么它也会被用作默认的ResourceLoader 。这通常是org.springframework.context.ApplicationContext实现的情况。
* 如果给定一个普通的BeanDefinitionRegistry ,默认的ResourceLoader将是一个org.springframework.core.io.support.PathMatchingResourcePatternResolver 。
* @param registry 以BeanDefinitionRegistry的形式将 bean 定义加载到其中的BeanFactory
* @param useDefaultFilters 是否包含@Component 、 @Repository 、 @Service和@Controller原型注解的默认过滤器
* @param environment 评估 bean 定义配置文件元数据时使用的 Spring Environment
*/
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
Environment environment) {
this(registry, useDefaultFilters, environment,
(registry instanceof ResourceLoader ? (ResourceLoader) registry : null));
}
/**
* 为给定的 bean 工厂创建一个新的ClassPathBeanDefinitionScanner ,并在评估 bean 定义配置文件元数据时使用给定的Environment 。
* @param registry 以BeanDefinitionRegistry的形式将 bean 定义加载到其中的BeanFactory
* @param useDefaultFilters 是否包含@Component 、 @Repository 、 @Service和@Controller原型注解的默认过滤器
* @param environment 评估 bean 定义配置文件元数据时使用的 Spring Environment
* @param resourceLoader 要使用的ResourceLoader
*/
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
Environment environment, @Nullable ResourceLoader resourceLoader) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
this.registry = registry;
if (useDefaultFilters) {
registerDefaultFilters();
}
setEnvironment(environment);
setResourceLoader(resourceLoader);
}
private static Environment getOrCreateEnvironment(BeanDefinitionRegistry registry) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
if (registry instanceof EnvironmentCapable) {
return ((EnvironmentCapable) registry).getEnvironment();
}
return new StandardEnvironment();
}
/**
* 在解析占位符和评估@Conditional组件类时设置要使用的环境。默认值为StandardEnvironment 。
*/
public void setEnvironment(Environment environment) {
Assert.notNull(environment, "Environment must not be null");
this.environment = environment;
this.conditionEvaluator = null;
}
/**
* 设置ResourceLoader以用于资源位置。这通常是ResourcePatternResolver实现。默认是PathMatchingResourcePatternResolver ,也能够通过ResourcePatternResolver接口解析资源模式。
*/
@Override
public void setResourceLoader(@Nullable ResourceLoader resourceLoader) {
this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
this.metadataReaderFactory = new CachingMetadataReaderFactory(resourceLoader);
this.componentsIndex = CandidateComponentsIndexLoader.loadIndex(this.resourcePatternResolver.getClassLoader());
}