上节我们分析到analyzers = new FailureAnalyzers(context);为止
我们接下去分析prepareContext
这段代码主要做了八件事
为上下文设置Environment. 注意 这里传入的是 StandardServletEnvironment
调用postProcessApplicationContext方法设置上下文的beanNameGenerator和resourceLoader(如果SpringApplication有的话)
拿到之前实例化SpringApplication对象的时候设置的ApplicationContextInitializer,调用它们的initialize方法,对上下文做初始化
调用listeners#contextPrepared,该方法是一个空实现
打印启动日志
往上下文的beanFactory中注册一个singleton的bean,bean的名字是springApplicationArguments,bean的实例是之前实例化的ApplicationArguments对象,
如果之前获取的printedBanner不为空,那么往上下文的beanFactory中注册一个singleton的bean,bean的名字是springBootBanner,bean的实例就是这个printedBanner.这里默认是SpringBootBanner.
调用load方法注册启动类的bean定义,也就是调用SpringApplication.run(Application.class, args);的类,SpringApplication的load方法内会创建BeanDefinitionLoader的对象,并调用它的load()方法
调用listeners的contextLoaded方法,说明上下文已经加载,该方法先找到所有的ApplicationListener,遍历这些listener,如果该listener继承了ApplicationContextAware类,那么在这一步会调用它的setApplicationContext方法,设置context
我们一句句分析
先看第一句话
context.setEnvironment(environment);
这句话没什么好说的,就是设置一些变量
postProcessApplicationContext(context);
SpringApplication#prepareContext 接下来执行的是 postProcessApplicationContext 方法.设置上下文的beanNameGenerator和resourceLoader(如果SpringApplication有的话).
applyInitializers(context);
----->
首先是获取到在SpringApplication中初始化的,Initializers,一共有六个,然后循环遍历他们的initialize方法。这里分析几个Initializers
DelegatingApplicationContextInitializer#initialize 会根据环境中有没有context.initializer.classes的配置项,来加载,这是一个扩展点,spring本身是没有的,需要我们自行配置,如果有的就会实例化,然后再调用他的initialize
ContextIdApplicationContextInitializer#initialize 这个方法就是设置contextId,具体规则不深究
ServerPortInfoApplicationContextInitializer#initialize 这个向applicationContext 添加一个监听.当发生EmbeddedServletContainerInitializedEvent事件时.会执行ServerPortInfoApplicationContextInitializer#onApplicationEvent方法.将server.ports添加到名为server.ports 的MapPropertySource
SharedMetadataReaderFactoryContextInitializer#initialize向applicationContext 添加了一个CachingMetadataReaderFactoryPostProcessor 的BeanFactoryPostProcessor 至于BeanFactoryPostProcessor的具体讲解,我们会在refresh方法中进行讲解。
剩余的Initializer就不说了
视线回到prepareContext方法,listeners.contextPrepared(context);这里是个空实现,EventPublishingRunListeners没有具体实现这个方法。
接着这段代码是打印相关日志。
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
//配置项相关日志
logStartupProfileInfo(context);
}
然后再spring容器中添加一些bean,我们直接看load方法
load(context, sources.toArray(new Object[sources.size()]));
这里的source就是启动类
直接跳到BeanDefinitionLoader方法中的
private int load(Class<?> source) {
if (isGroovyPresent()) {
// Any GroovyLoaders added in beans{} DSL can contribute beans here
if (GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source,
GroovyBeanDefinitionSource.class);
load(loader);
}
}
if (isComponent(source)) {
this.annotatedReader.register(source);
return 1;
}
return 0;
}
由于启动类中有configuration注解,所以是一个component注解类
public void registerBean(Class<?> annotatedClass, String name, Class<? extends Annotation>... qualifiers) {
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
}
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
abd.setScope(scopeMetadata.getScopeName());
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
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));
}
}
}
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}
我们慢慢跟踪
this.conditionEvaluator.shouldSkip(abd.getMetadata())
该代码判断Application上是否存在Conditional注解,如果不满足Conditional对应条件则该bean不被创建
、
Conditional注解
代码分析到这里可以先看看Conditional注解的使用,其定义为:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Conditional {
/**
* All {@link Condition}s that must {@linkplain Condition#matches match}
* in order for the component to be registered.
*/
Class<? extends Condition>[] value();
}
从源码可以看出,首先判断Application上是否存在Conditional,如果存在,则获取Conditional注解中的value数组值,对应的Class必须实现Condition接口:
public interface Condition {
boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}
如果matches返回true 表明该bean需要被创建,否则表明该bean不需要被创建。
明白了该注解的用法后,来一个实际案例
package com.lkl.springboot.condition;
import org.springframework.context.annotation.Conditional;
import org.springframework.stereotype.Component;
@Component("MyCondition")
@Conditional(MyCondition.class)
public class ConditionBean {
}
创建ConditionBean,使用注解@Conditional(MyCondition.class)调用MyCondition类
/**
* 自定义condition 修改返回值,查看bean是否创建
*
* @author liaokailin
*/
public class MyCondition implements Condition {
/**
* 返回true 生成bean
* 返回false 不生成bean
*/
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Map<String, Object> map = metadata.getAnnotationAttributes(Component.class.getName());
return "MyCondition".equals(map.get("value").toString());
}
}
MyCondition实现接口Condition,在matches方法中获取bean上注解Component信息,如果bean名称等于MyCondition返回true,否则返回false,bean不会被创建。
回到前面Application的分析,Application上不存在Conditional,因此shouldSkip返回false,代码继续执行
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
单例相关
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
这个方法比较复杂,总结一下就是处理一下常见的注解
处理Lazy、Primary、DependsOn、Role、Description等注解
直接跳到最后一步,把mian主类注册到spring容器中,也就是加入到beanDefinitionMap里面
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
视线回到prepareContext中
listeners.contextLoaded(context);
这里其实是调用EventPublishingRunListners的contextLoaded方法
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));
}
this.application.getListeners()这句话是老面孔,还是那10个linsteners,然后循环遍历,调用onApplicationEvent方法,此时发布的事件是ApplicationPreparedEvent类型事件
这一节完毕。。下一节我们将分析refresh方法,这是spring的重头戏。。将分成好几节讲