Spring Boot 启动过程:
1. 创建 SpringApplication 对象。
2. 执行对象的 run() 方法。
3. 将 class 变成 beanDefinition。
4. 将 beanDefinition 变成 bean
5. 图解 循环依赖
6. 图解 bean 的生命周期
7. 图解 aop 拦截器链调用
Spring Boot 在启动是执行了自动配置:class --> beanDefinition --> bean。这篇文章主要想梳理下:class 是怎么变成 beanDefinition 的。上一篇博客提到过,执行 run 方法中 invokeBeanFactoryPostProcessors(beanFactory)
方法执行了这一变换,看下这个方法了到了干了什么?
/** AbstractApplicationContext.java
Instantiate and invoke all registered BeanFactoryPostProcessor beans, respecting explicit order if given.
Must be called before singleton instantiation.
必须在 class 变成 bean 之前,按照给定的顺序(如果有)实例化所有已注册的 beanFactoryPostProcessor。
*/
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
// 执行每一个 beanFactoryPostProcessor。
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
if (!NativeDetector.inNativeImage() && beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
// 注册了一个beanPostProcessor。
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
// 设置类加载器。
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}
//--------------------------------------
// 从 context 中获取已有的 beanFactoryPostProcessor。
public List<BeanFactoryPostProcessor> getBeanFactoryPostProcessors() {
return this.beanFactoryPostProcessors;
}
很明显了,接下来要看下 beanFactoryPostProcessor 是怎么执行的。
别看代码这么长,就解决了两个问题:
执行顺序:
public interface BeanFactoryPostProcessor {
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
// -----------------
public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
}
规则1:实现 BeanDefinitionRegistryPostProcessor
的类先执行,只实现 BeanFactoryPostProcessor
类的接口后执行。
规则2:在规则1 的基础上,实现 PriorityOrdered
的类先执行,实现 Ordered
的类后执行,最后执行既没实现 PriorityOrdered
,也没实现 Ordered
的类。
// 执行顺序
1. Class implements BeanDefinitionRegistryPostProcessor, PriorityOrdered;
2. Class implements BeanDefinitionRegistryPostProcessor, Ordered;
3. Class implements BeanDefinitionRegistryPostProcessor;
4. Class implements BeanFactoryPostProcessor, PriorityOrdered;
5. Class implements BeanFactoryPostProcessor, Ordered;
6. Class implements BeanFactoryPostProcessor;
执行了什么:
每一个 BeanFactoryPostProcessor 的实现类在这里只执行了接口方法。也就是说:
Class implements BeanDefinitionRegistryPostProcessor
先执行postProcessBeanDefinitionRegistry
方法,再执行postProcessBeanFactory
方法。
Class implements BeanFactoryPostProcessor
只执行 postProcessBeanFactory
方法。
从哪里拿的:
有两个地方:
第一种,可能 BeanFactoryPostProcessor 已经实例化成了 bean,那么它存放在 context 的 beanFactoryPostProcessors
属性中;
第二种,BeanFactoryPostProcessor还没有实例化,目前仅仅之是个“蓝图”(beanDefinition),那么它存放在 context 的 beanFactory
属性的 beanDefinitionMap
属性中。
接下来看下源码:
public static void invokeBeanFactoryPostProcessors(
// beanFactoryPostProcessors 是从 context 中直接拿的 bean。
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
// Invoke BeanDefinitionRegistryPostProcessors first, if any.
// 保存已经处理过的 beanName。
Set<String> processedBeans = new HashSet<>();
// beanFactory 是实例是 DefaultListableBeanFactory,它实现了 BeanDefinitionRegistry 接口。
if (beanFactory instanceof BeanDefinitionRegistry) {
// 向上转型
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
// 保存常规的 beanFactoryPostProcessor,没实现 BeanDefinitionRegistryPostProcessor 接口的都是常规的。
List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
// 保存非常规的 beanFactoryPostProcessor。
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
// 遍历已经注册的 beanFactoryPostProcessor。
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
// 判断是否是非常规的。如果是,那就具有优先执行权。
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
// 类型转换,不然拿不到方法。
BeanDefinitionRegistryPostProcessor registryProcessor =
(BeanDefinitionRegistryPostProcessor) postProcessor;
// 执行 postProcessBeanDefinitionRegistry
registryProcessor.postProcessBeanDefinitionRegistry(registry);
// 保存到 registryProcessors,为什么要保存?因为这货还有一个方法没执行呢。
registryProcessors.add(registryProcessor);
}
else {
// 如果 postProcessor 是常规的,那它优先级不够,先保存。
regularPostProcessors.add(postProcessor);
}
}
// 到这里,bean 形式的 beanFactoryPostProcessor 已经拿出来了,并且执行了最高优先级的方法。
// 接下来要拿 “蓝图” 形式的了。
// 用来保存 beanDefinition 形式的 BeanDefinitionRegistryPostProcessor。
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
// 从 beanDefinitionMap 中获取与 BeanDefinitionRegistryPostProcessor.class 类型匹配的 beanDefinition
// 的 name。
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
// 遍历
for (String ppName : postProcessorNames) {
// 判断 ppName 对应的 beanDefinition 是不是最高优先级。
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
// 如果是最高优先级,用 beanDefinition 创建 bean,并经创建出来的 bean 保存到 currentRegistryProcessors。
// beanFactory.getBean()先去 beanFactory 中找,有没有 ppName 对应的 bean,
// 如果有,直接拿出来;如果没有,先创建bean,并保存到 beanFactory,最后再将 bean 返回。
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
// ppName 添加到 processedBeans。
processedBeans.add(ppName);
}
}
// 如果有多个同时具备最最高优先级,那他们之间也是需要在排序的。(这个不是重点)
sortPostProcessors(currentRegistryProcessors, beanFactory);
// 保存到 registryProcessors。
registryProcessors.addAll(currentRegistryProcessors);
// 执行每一个 beanDefinitionRegistryPostProcessor 的 postProcessBeanDefinitionRegistry 方法。
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
// Class implements BeanDefinitionRegistryPostProcessor, PriorityOrdered 就算是执行完了。
// 清空 currentRegistryProcessors,因为后面还要用。
currentRegistryProcessors.clear();
// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
// 接下来执行:Class implements BeanDefinitionRegistryPostProcessor, Ordered
// 拿名字
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
// 遍历
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
// 拿出 beanDefinitionRegistryPostProcessor,并保存到 currentRegistryProcessors。
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
// 排序
sortPostProcessors(currentRegistryProcessors, beanFactory);
// 保存
registryProcessors.addAll(currentRegistryProcessors);
// 执行每一个 beanDefinitionRegistryPostProcessor 的 postProcessBeanDefinitionRegistry 方法。
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
// 清空
currentRegistryProcessors.clear();
// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
// 最后执行 Class implements BeanDefinitionRegistryPostProcessor
boolean reiterate = true;
while (reiterate) {
reiterate = false;
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
// 如果能拿到,当然还要执行循环。
reiterate = true;
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
currentRegistryProcessors.clear();
}
// registryProcessors 保存的是非常规的 beanFactoryPostProcessor,
// 它还有个 postProcessBeanFactory 没执行呢。
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
// 常规的 beanFactoryPostProcessor 也在这里执行 postProcessBeanFactory 方法。
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
}
else {
// Invoke factory processors registered with the context instance.
// 如果 beanFactory 没有实现 BeanDefinitionRegistry 接口,才会走到这里。
invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
}
/**
4. Class implements BeanFactoryPostProcessor, PriorityOrdered;
5. Class implements BeanFactoryPostProcessor, Ordered;
6. Class implements BeanFactoryPostProcessor;
流程跟 1、2、3 几乎是一样的,就不写了注释了。
*/
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
// Ordered, and the rest.
List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
if (processedBeans.contains(ppName)) {
// skip - already processed in first phase above
}
else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}
// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
// Next, invoke the BeanFactoryPostProcessors that implement Ordered.
List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
for (String postProcessorName : orderedPostProcessorNames) {
orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
sortPostProcessors(orderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
// Finally, invoke all other BeanFactoryPostProcessors.
List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
for (String postProcessorName : nonOrderedPostProcessorNames) {
nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
// Clear cached merged bean definitions since the post-processors might have
// modified the original metadata, e.g. replacing placeholders in values...
// 清缓存
beanFactory.clearMetadataCache();
}
这一层的代码逻辑还是很简单的。不过接下来会出现一个货,很重要也和复杂。
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
PriorityOrdered, ResourceLoaderAware, ApplicationStartupAware, BeanClassLoaderAware, EnvironmentAware {
// 属性和方法就省略了,看它实现的接口就明白了。
}
ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,PriorityOrdered
说明这个类在 上面的代码中肯定是先执行了 postProcessBeanDefinitionRegistry()
后执行了 postProcessBeanFactory()
,而且还是以最高优先级执行的。 在postProcessBeanDefinitionRegistry()
方法执行的时候,它将需要自动配置的 class 变成了 bean。
在 run() 方法中实例化 context 时,框架就默认加载了 一些 beanDefinition 并保存在 context 的 beanFactory
属性的 definitionMap
属性中。
// 被加载部分的 beanDefinition
"org.springframework.context.annotation.internalConfigurationAnnotationProcessor" \
= ConfigurationClassPostProcessor.class; //(看这里)
"org.springframework.context.event.internalEventListenerFactory" \
= DefaultEventListenerFactory.class;
"org.springframework.context.event.internalEventListenerProcessor" \
= EventListenerMethodProcessor.class;
"org.springframework.context.annotation.internalAutowiredAnnotationProcessor" \
= AutowiredAnnotationBeanPostProcessor.class;
"org.springframework.context.annotation.internalCommonAnnotationProcessor" \
= CommonAnnotationBeanPostProcessor.class;
具体的加载流程如下:
// springApplition.java ------------------- 1
public ConfigurableApplicationContext run(String... args) {
//......上面省略.......
context = createApplicationContext();
//......下面省略.......
}
// springApplition.java ------------------- 2
protected ConfigurableApplicationContext createApplicationContext() {
return this.applicationContextFactory.create(this.webApplicationType);
}
// ApplicationContextFactory.java --------- 3
ApplicationContextFactory DEFAULT = (webApplicationType) -> {
try {
switch (webApplicationType) {
case SERVLET:
// 走这里,context的实际类型是 AnnotationConfigServletWebServerApplicationContext。
return new AnnotationConfigServletWebServerApplicationContext();
case REACTIVE:
return new AnnotationConfigReactiveWebServerApplicationContext();
default:
return new AnnotationConfigApplicationContext();
}
}
catch (Exception ex) {
throw new IllegalStateException("Unable create a default ApplicationContext instance, "
+ "you may need a custom ApplicationContextFactory", ex);
}
};
// AnnotationConfigServletWebServerApplicationContext.java ----- 4
// 这是构造器。
public AnnotationConfigServletWebServerApplicationContext() {
// reader 读取了那四个 beanDefinition。
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
// AnnotatedBeanDefinitionReader.java -------------------------- 5
// 这也是构造器。
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
this(registry, getOrCreateEnvironment(registry));
}
// AnnotatedBeanDefinitionReader.java -------------------------- 6
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
//......上面省略.......
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
// AnnotationConfigUtils.java ---------------------------------- 7
public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
registerAnnotationConfigProcessors(registry, null);
}
// AnnotationConfigUtils.java ---------------------------------- 8
public static final String CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME =
"org.springframework.context.annotation.internalConfigurationAnnotationProcessor";
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, @Nullable Object source) {
//......上面省略.......
// registry 就是 beanFactory, 判断 beanFactory 有没有?
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
// 如果没有,构造 ConfigurationClassPostProcessor 的 beanDefinition。
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
def.setSource(source);
// registerPostProcessor()将键值对CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME:def 注册到 registory 中。
beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// 其他三个也是这么注册进去的,这里就不贴代码了。
}
写到这里还是能说的通的,ConfigurationClassPostProcessor
在 context 实例化时就以 beanDefinition 的形式注册到了 beanFactory 中。在 invokeBeanFactoryPostProcessors() 方法中,根据 ConfigurationClassPostProcessor.class
去 beanFactory 中找匹配的 beanDefinition,再去 beanFactory 中拿对应的bean,没有拿到,所以就根据 beanDefinition 创建了 ConfigurationClassPostProcessor
对应的 bean,最后执行其 processConfigBeanDefinitions(BeanDefinitionRegistry registry)
方法,完成了需要自动配置的类的注册。
class --> bean 阶段中最复杂的地方出现了,不过还是尽量将这块的内容写清楚。
/** ConfigurationClassPostProcessor.java
从配置类中生成 beanDefinition 注册到 registory 中。
入口参数的 registry 实际上是 DefaultListableBeanFactory。
*/
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
int registryId = System.identityHashCode(registry);
if (this.registriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
}
if (this.factoriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + registry);
}
this.registriesPostProcessed.add(registryId);
// 上面代码都不重要,从这里开始看,处理配置 beanDefinition。
processConfigBeanDefinitions(registry);
}
看下面源码之前,先说一个小细节,不然会懵的。启动类(被@SpringBootApplication
注解的类)的 beanDefinition 在执行 run()
方法中的 prepareContext()
方法中的 load(context, sources.toArray(new Object[0]))
方法时,被注册到了 beanFactory
中。
/** ConfigurationClassPostProcessor.java
registry 实际上是 DefaultListableBeanFactory 类型的对象。
*/
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
// BeanDefinitionHolder 是对 BeanDefinition 的包装。
// configCandidates 用来保存所有的需要自动配置的类的 beanDefinitionHolder。
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
// 获取已经注册的所有 beanDefinition 的 name。
String[] candidateNames = registry.getBeanDefinitionNames();
// 遍历 candidateNames
for (String beanName : candidateNames) {
// 依据 beanName 从 beanFactory 中拿对应的 beanDefinition。
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
// 判断 beanDefinition 中有没有 “org.springframework.context.annotation.ConfigurationClassPostProcessor.configurationClass” 属性?
// (实际测试的结果是都没有这个属性)
if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
if (logger.isDebugEnabled()) {
//(根据这里的日志推测,上面是在检查:beanDef是不是已经作为配置类处理过了?)
logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
}
// 检查 beanDef 是否是个配置类的候选者,如果是做个标记。
// beanDef 拥有 @Configuration 或 @Component 或 @ComponentScan 或 @Import 或 @ImportResource 其中的
// 一个注解,那它就是配置类的后选择。
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
// 将配置类后选者 beanDef 添加到 configCandidates 中。
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
//(上面测试的结果是:只有主启动类对应的 beanDefinition 添加到了configCandidates 中。)
// Return immediately if no @Configuration classes were found
// 如果没有配置后选择,也就是说已注册的 beanDefinition 都不需要自动配置,那么直接返回吧。
if (configCandidates.isEmpty()) {
return;
}
// Sort by previously determined @Order value, if applicable
// 对 configCandidates 中元素依据 @Order 注解进行排序。
configCandidates.sort((bd1, bd2) -> {
int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
return Integer.compare(i1, i2);
});
// Detect any custom bean name generation strategy supplied through the enclosing application context
/**
这里是创造一个 beanName 生成器。具体规则如下:
1. 先在 applicationContext 中找有没有自定义的 bean name 生成器。(默认没有自定义的)
2. 如果没有自定义的,那就使用默认的。
默认情况下:
- componentScanBeanNameGenerator 使用简短的类名作为 bean name。
- importBeanNameGenerator 使用全限定类名作为 bean name。
*/
SingletonBeanRegistry sbr = null;
if (registry instanceof SingletonBeanRegistry) {
sbr = (SingletonBeanRegistry) registry;
if (!this.localBeanNameGeneratorSet) {
BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(
AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
if (generator != null) {
this.componentScanBeanNameGenerator = generator;
this.importBeanNameGenerator = generator;
}
}
}
// 设置环境属性。
if (this.environment == null) {
this.environment = new StandardEnvironment();
}
// Parse each @Configuration class
// 创建配置类解析器 parser,后面就是使用它 寻找 并 解析 所有的配置类。
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
// 拷贝一份 configCandidates,后面要使用。里面只有一个主启动类的 beanDefinitionHolder。
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
// alreadyParsed 保存已经解析到配置类。
Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
do {
// 记录阶段信息,
StartupStep processConfig = this.applicationStartup.start("spring.context.config-classes.parse");
// 执行解析(里面很复杂, 只解析了程序员开发的需要自动配置的类)
/**
candidates 中是主配置类,因为上面有@ComponentScan、和 @EnableAutoConfiguration 所以执行了
基包下类的解析和 MEDA-INFO/spring.factories 文件中的 EnableAutoConfiguration 类的解析。
需要解析的类可以分为两种,第一种是程序员自己写的需要自动配置的;第二种是框架默认的,保存在“MEDA-INFO/spring.factories” 中。
程序员自己写的,parser 将类解析成 ConfigurationClass 对象,和 BeanDefinition 对象,前者保存在 parser 的
configurationClasses 属性中,后者 保存(注册)在 beanFactory 的 beanDefinitionMap 属性中。(算是解析完了)。
框架默认的,parser 只将其解析成 ConfigurationClass 对象,也保存在 parser 的
configurationClasses 属性中,但还没弄成 beanDefinition。(解析未完成)。
*/
parser.parse(candidates);
// 每个需要自动配置的 class 会被解析成 ConfigurationClass 对象,并保存在 parser 中,
// 这里是校验所有解析到的 ConfigurationClass 对象。(至于怎么校验的,忽略它吧)
parser.validate();
// 将 parser 解析到的所有 ConfigurationClass 对象拷贝一份到 configClasses,后面要用。
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
// 第一次循环,alreadyParsed 是空的,但如果有第二次、第三次循环 alreadyParsed 就不为空了。
configClasses.removeAll(alreadyParsed);
// Read the model and create bean definitions based on its content
// 上面说道过,configClasses 中一部分已经有了对应的 beanDefinition,一部分还没有。
// 如果要为没有的那部分新建 beanDefinition,那得先创建个读对象。
if (this.reader == null) {
// (看这个名字,都能感觉到它跟创建 BeanDefinition 有关。)
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
// 给 configClasses 中的元素载入 beanDefinition。如果元素有 beanDefinition,那跳过,如果没有就新建。
this.reader.loadBeanDefinitions(configClasses);
// 到这里,configClasses 中的元素都已经解析完成了。
alreadyParsed.addAll(configClasses);
processConfig.tag("classCount", () -> String.valueOf(configClasses.size())).end();
// 配置类候选者被解析完了,要清空的,否则后面再添加就说不清楚了。
candidates.clear();
/**
这里主要是检查下有没有遗漏的配置类。
*/
// 只要往 beanDifinitionMap 中添加了新的 beanDefinition,if 判断绝对是成立的。
if (registry.getBeanDefinitionCount() > candidateNames.length) {
// newCandidateNames:此时 beanDifinitionMap 所有 beanDefinition 的 name。
String[] newCandidateNames = registry.getBeanDefinitionNames();
// oldCandidateNames:执行解析前 beanDifinitionMap 所有 beanDefinition 的 name。
Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
// alreadyParsedClasses: 保存刚才已经完成解析的所有的 configurationClass 的 name。
Set<String> alreadyParsedClasses = new HashSet<>();
// 遍历 alreadyParsed,拿出每个元素的 name 保存到 alreadyParsedClasses。
for (ConfigurationClass configurationClass : alreadyParsed) {
alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
}
// (真正的检查遗漏要开始了)
// 遍历全部的 beanDefinition 的 name。
for (String candidateName : newCandidateNames) {
// candidateName 对应的 beanDefinition 不是最初的。
if (!oldCandidateNames.contains(candidateName)) {
// 将这个 beanDefinition 拿出来。
BeanDefinition bd = registry.getBeanDefinition(candidateName);
// 再判断:(bd 满足配置类条件,但还没有被解析?)
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
!alreadyParsedClasses.contains(bd.getBeanClassName())) {
// 如果真是这样,那 bd 就是被遗漏的 beanDefinition 了。要循环一次再将其解析。
candidates.add(new BeanDefinitionHolder(bd, candidateName));
}
}
}
// 无论循环与否,这个都应该更新。
candidateNames = newCandidateNames;
}
}
while (!candidates.isEmpty());
// Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
// 这里是直接给 beanFactory 中的 singletonObject 属性添加了一个 bean。
if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
}
// 解析完了,清缓存。
if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
// Clear cache in externally provided MetadataReaderFactory; this is a no-op
// for a shared cache since it'll be cleared by the ApplicationContext.
((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
}
}
到这里 ConfigurationClassPostProcessor
的 processConfigBeanDefinitions(BeanDefinitionRegistry registry)
方法的整个执行就梳理完了,至于更细节的东西,下面再写。
这里应该能明白一个问题了:为什么要先执行 processConfigBeanDefinitions()
方法,后执行 postProcessBeanFactory()
方法?
因为后者是修改 beanDefinition 的,而前者是创建 beanDefinition 的。想修改,你得先有个吧。
在 3.2 的代码中,还有几个细节需要再往下走一层,再看看细节:
- 怎么判定一个 beanDefinition 是不是满足配置类候选者?
parser.parse(candidates);
方法是怎么解析配置类后选择的?(只送进去一个启动类,结果解析了一大堆)。this.reader.loadBeanDefinitions(configClasses);
是怎么载入 beanDefinition 的?他们各自分别对应了一个方法,再往下走一层,看看。
/** ConfigurationClassUtils.java
检查给定的 beanDefinition 是不是一个配置类的候选者,如果给定的 beanDefinition 是内嵌到配置类(组件类)中的组件类,也要被自动注册的。
*/
public static boolean checkConfigurationClassCandidate(
BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {
// 获取类名。
String className = beanDef.getBeanClassName();
// 类名为空 或者 beanDefinition 中有工厂方法,那么该 beanDefinition 不是配置类的后选择。
if (className == null || beanDef.getFactoryMethodName() != null) {
return false;
}
// metadata 用来保存既有注解信息,又有类信息。(beanDefinition 保存着 class 的所有信息,当然也包括注解信息。)
AnnotationMetadata metadata;
/**
接下来就是依据配置类的不同形式,获取注解信息。
这块是我猜的:一个配置类有 基于javaConfig类型的,有使用xml文件的,或者还有其他类型的。
这些不同形式的配置类都得先翻译 beanDefinition,从而就出现了不同类型的 BeanDefinition。
所以,下面先判断了给定的 beanDefinition 的类型,再从里面读注解信息。
*/
if (beanDef instanceof AnnotatedBeanDefinition &&
className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) {
// Can reuse the pre-parsed metadata from the given BeanDefinition...
// 被 @SpringBootApplication 注解的启动类的 beanDefinition 属于这种类型。
metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();
}
else if (beanDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) beanDef).hasBeanClass()) {
// Check already loaded Class if present...
// since we possibly can't even load the class file for this Class.
Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass();
if (BeanFactoryPostProcessor.class.isAssignableFrom(beanClass) ||
BeanPostProcessor.class.isAssignableFrom(beanClass) ||
AopInfrastructureBean.class.isAssignableFrom(beanClass) ||
EventListenerFactory.class.isAssignableFrom(beanClass)) {
return false;
}
metadata = AnnotationMetadata.introspect(beanClass);
}
else {
try {
MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(className);
metadata = metadataReader.getAnnotationMetadata();
}
catch (IOException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Could not find class file for introspecting configuration annotations: " +
className, ex);
}
return false;
}
}
/**
执行到这里,注解信息是肯定拿到了,如果拿不到,在上面就返回了。
那下面的代码就是要根据注解判断 beanDefinition 是不是配置类候选着。
*/
// 从 metadata 中拿 @Configuration 注解。
Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
// 如果能拿到 @Configuration 注解,且 @Configuration 注解中的 proxyBeanMethods 属性值是 true。
if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
// 配置类设置为 ’full‘模式,对应的 @Configuration(proxyBeanMethods=true)
// 被注解的类配置类是代理类,调被@Bean注解的方法时,会先去 signclObject 中拿,只有当 signclObject
// 拿不到时, 执行被@bean注解的方法。所以此模式下,多次拿同一个对象,拿到的都是一样的。
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
// (这里执行了,下面两个代码块就不会执行了,最后返回 true。说明,有 @configuration 注解,那就是配置类候选者。)
}
// 如果拿不到 @Configuration 注解,再判断下 metadata 是不是配置类候选者。
// 这 ”再判断是找“ 有没有被 @Component、@ComponentScan、@Import、@ImportResource 其中之一注解,
// 或者有没有被 @Bean注解的方法。如果有,那就是配置类后选择
else if (config != null || isConfigurationCandidate(metadata)) {
// 配置类设置为 ’lite‘ 模式,相当于 @Configuration(proxyBeanMethods=false)
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
// (同样的,被上面 5 个注解其中之一注解的类,也是配置类后选择。)
}
else {
// 否则,那就不是配置类后选择,直接返回 false。
return false;
}
// It's a full or lite configuration candidate... Let's determine the order value, if any.
// 设置顺序。
Integer order = getOrder(metadata);
if (order != null) {
beanDef.setAttribute(ORDER_ATTRIBUTE, order);
}
// 返回 true,表示规定的 beanDefinition 是配置类候选者。
return true;
}
// ----------------------------------
/** ConfigurationClassUtils.java
检查给定的 metadata 是不是配置类候选者。
*/
public static boolean isConfigurationCandidate(AnnotationMetadata metadata) {
// Do not consider an interface or an annotation...
// 如果是接口,那就不是配置类候选者,直接返回 false。
if (metadata.isInterface()) {
return false;
}
// Any of the typical annotations found?
// 如果被 @Component、@ComponentScan、@Import、@ImportResource 其中之一注解,
// 那就是配置类候选者,返回 true。
for (String indicator : candidateIndicators) {
if (metadata.isAnnotated(indicator)) {
return true;
}
}
// Finally, let's look for @Bean methods...
// 如果有被 @Bean 注解的方法,返回 true。否则返回 false。
return hasBeanMethods(metadata);
}
//-----------------------------------------
private static final Set<String> candidateIndicators = new HashSet<>(8);
static {
candidateIndicators.add(Component.class.getName());
candidateIndicators.add(ComponentScan.class.getName());
candidateIndicators.add(Import.class.getName());
candidateIndicators.add(ImportResource.class.getName());
}
这个方法就算是梳理完了。简单总结一下:
@Configuration
、@Component
、@ComponentScan
、@Import
、@ImportResource
以及 @bean注解了方法
的类都是配置类候选者;@Configuration(proxyBeanMethods=true)
的配置类是 full
模式,除此以外都是 lite
模式。full
模式和 lite
模式的区别:https://blog.csdn.net/demon7552003/article/details/107988310?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_title-0&spm=1001.2101.3001.4242。这里先要说明一件事情,不然没法往下写。parser() 方法的目的是将配置类解析成 beanDefinition并注册,那入口参数里已经包含了 beanDefinition 了,而且还是已经注册了的,那还解析个什么?
因为 parser 解析的不是入口参数送进来的配置类。 比如入口参数送进来的配置类上有 @Import(Another.class)
注解,那 Another.class
也是要被解析成对应的 beanDefinition 的。再比如入口参数送进来的是启动类,上面有 @ComponentScan
注解,那可是要以启动类所在的包为基包,递推扫描基包目录及其子目录下的所有配置类,为其创建 beanDefinition。
入口参数给的 configCandidates 不过只是个解析的入口而已(而且也应该有个入口),后面要做的事情才是重点。
接下来梳理下 parser 的细节。
/** ConfigurationClassParser.java
与其说这里是在解析配置类,倒不如说这里是在解析配置类上的注解,并执行注解对应的操作。
*/
public void parse(Set<BeanDefinitionHolder> configCandidates) {
// 遍历每一个配置类的 BeanDefinitionHolder。
for (BeanDefinitionHolder holder : configCandidates) {
// 把 beanDefiniton 拿出来。
BeanDefinition bd = holder.getBeanDefinition();
try {
// (依据 beanDefinition 的类型,执行不同的 parser)
if (bd instanceof AnnotatedBeanDefinition) {
// 如果是 AnnotatedBeanDefinition 类型。(启动类就是这种类型)
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
}
else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
// 如果是 AbstractBeanDefinition 类型。
parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
}
else {
// 其余类型。
parse(bd.getBeanClassName(), holder.getBeanName());
}
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
}
}
// 上面解析的基本都是程序员自己开发的类,通过启动类的 @ComponentScan 注解递归递归基包下的所有配置类。
//----------------- 分界线 --------------
// 下面解析的部分框架默认的,那些写在 META-INF/spring.factories 文件中的 EnableAutoConfiguration 的子类,
// 为什么只解析部分?
// 因为好些类上都有 @Conditional 注解,只有满足其条件的才能解析那些类。
//(这个方法我测试了下,具体的细节没有看)
this.deferredImportSelectorHandler.process();
}
//-------------------------
/** ConfigurationClassParser.java
很明显,三个 parser 方法虽然入口参数不一样,但是都构建成 ConfigurationClass 对象,
然后送入 processConfigurationClass() 中执行。
*/
// parse1
protected final void parse(@Nullable String className, String beanName) throws IOException {
Assert.notNull(className, "No bean class name for configuration class bean definition");
MetadataReader reader = this.metadataReaderFactory.getMetadataReader(className);
processConfigurationClass(new ConfigurationClass(reader, beanName), DEFAULT_EXCLUSION_FILTER);
}
// parse2
protected final void parse(Class<?> clazz, String beanName) throws IOException {
processConfigurationClass(new ConfigurationClass(clazz, beanName), DEFAULT_EXCLUSION_FILTER);
}
// parse3
// 启动类会执行这个方法。
protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
// 使用 metadata 和 beanName 创建 ConfigurationClass 对象,送到 processConfigurationClass 方法中去解析。
processConfigurationClass(new ConfigurationClass(metadata, beanName), DEFAULT_EXCLUSION_FILTER);
}
这里得先说一下大体流程,processConfigurationClass() 方法里面使用了递归,不然看不清楚。在程序刚启动时,configCandidates 肯定是启动类,所以先会走 parse3 方法,因为要扫描基包下的其他组件并解析(在这块会递归),所以在解析其他组件时优惠掉过头来执行 parse1 或者 parse2。
/** ConfigurationClassParser.java
processConfigurationClass() 主要做流程控制,里面的 doProcessConfigurationClass() 是真正负责解析的。
记住:当前的代码块是在解析器中。
*/
protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
// 判断 configClass 中有没有 @Conditional 注解,并且当前环境是是否满足其条件,如果不满足,那 configClass 不解析。
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
// 直接返回。
return;
}
/**
这块代码主要主判断 configClass 是不是已经被解析了,如果没有还被解析,直接执行后面的代码。
*/
// 先从 configurationClasses 中拿一下,看是否能拿到。(如果没有被解析,当然拿不到,所以启动类肯定是从里面拿不到的)
ConfigurationClass existingClass = this.configurationClasses.get(configClass);
// 如果已经被解析了
if (existingClass != null) {
// 再判断 configClass 是通过 @Import 注解要注册的。
if (configClass.isImported()) {
// 如果 existingClass 也是通过 @Import 注解 注册的。
if (existingClass.isImported()) {
// 合并两个 ConfigurationClass 对象。
existingClass.mergeImportedBy(configClass);
}
// Otherwise ignore new imported config class; existing non-imported class overrides it.
// 无论是两者合并,还是值只以 existingClass 为准,到这里 configClass 就被解析完了,直接返回。
return;
}
else {
// Explicit bean definition found, probably replacing an import.
// Let's remove the old one and go with the new one.
// 如果 configClass 不通过 @Import 注解要注册,
// 那么先得从 configurationClasses 中将 configClass 的信息移除。(因为接下来要重新加进去)
this.configurationClasses.remove(configClass);
this.knownSuperclasses.values().removeIf(configClass::equals);
}
}
/**
接下来要正真开始解析 configClass。使用循环处理 configClass 的超类。
do{...} 中的 sourceClass 代表超类,如果不为null,那就还需要循环再处理超类,
超类可能还有超类....., 一直循环处理,直到 sourceClass == null,表示 configClass 解析完了。
除此以外,doProcessConfigurationClass() 方法内部使用了递归。
*/
// Recursively process the configuration class and its superclass hierarchy.
// SourceClass 类型是对配置类的简单包装,目的是让不同的配置类以统一的方式被调用。
SourceClass sourceClass = asSourceClass(configClass, filter);
do {
sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
}
while (sourceClass != null);
// configClass解析完后,构建 configClass:configClass 键值对保存到 configurationClasses 中。
this.configurationClasses.put(configClass, configClass);
}
这层看完后,肯定还有个疑惑 doProcessConfigurationClass(configClass, sourceClass, filter)
干了嘛啊。去里面看看。
前面提到过,送进来的配置类已经是注册了的 beanDefinition ,目下处理的是它上面的其他注解,以及它的父类、接口啥的。到这里可以感觉到 SpringBoot 中的注解,起到了一个“标记” 的功能,当程序启动时,如果看到类上有它“认识”的注解,就执行一段对应的逻辑代码,而不是注解内部写了什么逻辑代码,对被它注解的类执行对应操作。
protected final SourceClass doProcessConfigurationClass(
ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
throws IOException {
// 如果有 @Compenent,执行对应的逻辑。
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
// Recursively process any member (nested) classes first
processMemberClasses(configClass, sourceClass, filter);
}
// Process any @PropertySource annotations
// 如果有 @PropertySource 执行对应的逻辑。
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), PropertySources.class,
org.springframework.context.annotation.PropertySource.class)) {
if (this.environment instanceof ConfigurableEnvironment) {
processPropertySource(propertySource);
}
else {
logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
"]. Reason: Environment must implement ConfigurableEnvironment");
}
}
// Process any @ComponentScan annotations
// 如果有 @ComponentScan,这个要递归扫描基包下的目录及其子目录的。(一石激起千层浪)
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
if (!componentScans.isEmpty() &&
!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
for (AnnotationAttributes componentScan : componentScans) {
// The config class is annotated with @ComponentScan -> perform the scan immediately
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
// Check the set of scanned definitions for any further config classes and parse recursively if needed
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
// 执行了递归,调用 parse1 方法。基包下的每一个满足条件的组件都是需要解析的。
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
// Process any @Import annotations
// 如果有 @Import 注解,执行对应逻辑。
processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
// Process any @ImportResource annotations
AnnotationAttributes importResource =
AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
if (importResource != null) {
String[] resources = importResource.getStringArray("locations");
Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
for (String resource : resources) {
String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
configClass.addImportedResource(resolvedResource, readerClass);
}
}
// Process individual @Bean methods
// 如果有被 @Bean 注解的方法,执行对应逻辑。
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
// Process default methods on interfaces
// 处理当前类实现的接口们。
processInterfaces(configClass, sourceClass);
// Process superclass, if any
// 如果有超类,返回超类的 sourceClass, 要做递归的。
if (sourceClass.getMetadata().hasSuperClass()) {
String superclass = sourceClass.getMetadata().getSuperClassName();
if (superclass != null && !superclass.startsWith("java") &&
!this.knownSuperclasses.containsKey(superclass)) {
this.knownSuperclasses.put(superclass, configClass);
// Superclass found, return its annotation metadata and recurse
return sourceClass.getSuperClass();
}
}
// No superclass -> processing is complete
// 到这里就表示没有超类,真解析完了。
return null;
}
这一层就算是“大体”梳理完了,因为 每个注解对应的处理逻辑是怎么样的,这个还没有写。
不过地方已经知道了,如果想看哪个注解的更详细的处理逻辑,建议先去做几个demo,看一些原理相关的资料,有个大体理解过后,再回过头来看对应的源码是怎么走的。
有两个地方没有写出来:
每个注解对应的具体执行逻辑还没有写。
META-INFO/spring.factories 文件中默认的 EnableAutoconfiguration 的那些类被加载的具体源码过程,debug 的结果默认的:自动配置的类在前后两个地方被执行过,最终完成了注册。
ConfigurationClassPostProcessor.java
的 parse(Set configCandidates)
方法中的 this.deferredImportSelectorHandler.process();
语句ConfigurationClassPostProcessor.java
的 processConfigBeanDefinitions(BeanDefinitionRegistry registry)
方法中的 this.reader.loadBeanDefinitions(configClasses);
语句。后面补上。