接着上一篇,现在主要来看一下prepareContext方法的内容,先看代码:
prepareContext执行过程
private void prepareContext(ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
// 设置环境配置
context.setEnvironment(environment);
postProcessApplicationContext(context);
// 初始化实现类调用
applyInitializers(context);
// 事件传播
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
context.getBeanFactory().registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
}
// 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()
如果在初始化SpringApplication时有指定beanName生成器与资源加载器,这里会把其注册到beanFactory上;但我们这里都没有指定,所以该方法什么也不做。
applyInitializers()
我们在初始化SpringApplication时,通过getSpringFactoriesInstances方法查找classpath下的ApplicationContextInitializer的实现类应该还有印象吧。这里其实就是回调该接口的实现,并传入参数context。
protected void applyInitializers(ConfigurableApplicationContext context) {
for (ApplicationContextInitializer initializer : getInitializers()) {
Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(
initializer.getClass(),ApplicationContextInitializer.class);
// 回调
initializer.initialize(context);
}
}
接着就是把该阶段(context准备)的事件广播,然后把之前初始化的参数对象及banner打印注册到容器上。然后看一下load方法
load()
这里我不再贴代码,简单介绍一下该方法做了哪些。 首先,我们知道source数组这里其实只有一个元素,就是我们的启动类。load方法先创建了一个BeanDefinitionLoader类,其初始化过程有点类似之前分析的applicationcontext,也是指定了reader, scanner解析类等。比如这里指定了AnnotatedBeanDefinitionReader来解析带有@Component注解的类。因为这里的source是我们的启动类,所以实际就把@SpringBootApplication的类解析成beanDefinition注册到容器上。ok,知道它干了什么就行。但这里既然提到了AnnotatedBeanDefinitionReader类,那我们就详细了解一下它是具体内容。
AnnotatedBeanDefinitionReader
之前的内容中,已介绍过其初始化的过程,里面有两个成员变量beanNameGenerator,scopeMetadataResolver来作beanName生成,scope解读的。下面看一下它的核心方法registerBean
public void registerBean(Class<?> annotatedClass) {
doRegisterBean(annotatedClass, null, null, null);
}
调用doRegisterBean方法,如下
<T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
@Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
}
// 设置回调
abd.setInstanceSupplier(instanceSupplier);
//解析scope
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
abd.setScope(scopeMetadata.getScopeName());
// 生成beanName
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
//注解属性处理 @Lazy, @Primary, @DependsOn
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
// 处理传入的注解属性
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));
}
}
}
//自定义扩展实现回调
for (BeanDefinitionCustomizer customizer : definitionCustomizers) {
customizer.customize(abd);
}
// 包装definition
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
// 根据scope注册不同的代理模式beanDefinition
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
// 注册
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}
上面的方法相对比较简单,AnnotatedGenericBeanDefinition是beanDefinition的一个扩展实现,增加了收集注解的元数据信息。而关于代理模式的使用,这里不再详述。到这里,我们基本了解了一个被@Component注解的bean是怎么被解析beanDefinition,那下面再看一下是怎么注册到beanFactory的。
registerBeanDefinition
通过方法名可以猜到,它出自BeanDefinitionRegistry接口;跟踪该方法的实现,发现它到了DefaultListableBeanFactory这里,该类之前初始化过程已分析过,知道它维护了一个map类型的成员变量beanDefinitionMap。下面看一下注册代码:
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException {
// 主要是方法注入的校验
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
BeanDefinition oldBeanDefinition;
// 从map中查询是否已存在注册bean
oldBeanDefinition = this.beanDefinitionMap.get(beanName);
// 如果已存在,各种日志输出...
if (oldBeanDefinition != null) {
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
"': There is already [" + oldBeanDefinition + "] bound.");
}
else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
if (this.logger.isWarnEnabled()) {
this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
"' with a framework-generated bean definition: replacing [" +
oldBeanDefinition + "] with [" + beanDefinition + "]");
}
}
else if (!beanDefinition.equals(oldBeanDefinition)) {
if (this.logger.isInfoEnabled()) {
this.logger.info("Overriding bean definition for bean '" + beanName +
"' with a different definition: replacing [" + oldBeanDefinition +
"] with [" + beanDefinition + "]");
}
}
else {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Overriding bean definition for bean '" + beanName +
"' with an equivalent definition: replacing [" + oldBeanDefinition +
"] with [" + beanDefinition + "]");
}
}
// 覆盖
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
// 检查factory的bean创建解析过程是否已开始,是则需要同步
if (hasBeanCreationStarted()) {
synchronized (this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
if (this.manualSingletonNames.contains(beanName)) {
Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
updatedSingletons.remove(beanName);
this.manualSingletonNames = updatedSingletons;
}
}
}
else {
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
this.manualSingletonNames.remove(beanName);
}
this.frozenBeanDefinitionNames = null;
}
if (oldBeanDefinition != null || containsSingleton(beanName)) {
// 如果bean被覆盖或者已实例化,重置一下
resetBeanDefinition(beanName);
}
}
从代码可以看到,注册beanDefinition其实就是将其放入map中以待后续解析实例化。这里注意当解析实例化工作已启动时需要同步处理。对已存在的beanDefinition或者bean实例则重置。bean的实例化后面碰到再详细分析,这里不再详述。
到这里,我们分析了context的创建与准备,但基本都是spring的一些环境配置,资源加载器,beanDefinition解析器设置等相关的准备功能,即使加载注册部分beanDefinition也是内置处理器或启动类,真正解析我们自己写的类则还没开始解析,包括bean生命周期等。那么接下来的refreshContext方法则就是做这些工作的,下篇我们着重来跟踪分析一下代码。