spring5源码篇(4)——beanFactoryPostProcessor执行/注解bean的装配
创始人
2024-06-01 04:04:03
0

spring-framework 版本:v5.3.19

前面研究了beanDefinition的注册,但也仅仅是注册这一动作。那么在spring容器启动的过程中,是何时/如何装配的?以及装配的bean是如何注入的?
(考虑到xml方式基本不用了以及篇幅问题,所以本篇只看注解方式AnnotationConfigApplicationContext。)

文章目录

  • 何时装配
    • beanFactoryPostProcessor的执行入口
    • ConfigurationClassPostProcessor的注册
  • 如何装配
    • 主流程
    • 解析配置类
    • 加载配置类配置的beanDefinition
  • 总结

何时装配

beanFactoryPostProcessor的执行入口

实际上@Bean、@ComponentScan、@Import配置的bean装配逻辑是在ConfigurationClassPostProcessor实现的。这个类实现了BeanDefinitionRegistryPostProcessor接口,且又因为该接口继承自BeanFactoryPostProcessor,所以ConfigurationClassPostProcessor就是一个BeanFactoryPostProcessor。

BeanDefinitionRegistryPostProcessor 提供了一个回调方法 postProcessBeanDefinitionRegistry(),可以在这个方法中对 BeanDefinition 进行修改或者添加新的 BeanDefinition。

单从装配上来说,把ConfigurationClassPostProcessor认为是BeanDefinitionRegistryPostProcessor会比BeanFactoryPostProcessor更贴切。虽然BeanDefinitionRegistryPostProcessor继承自BeanFactoryPostProcessor,但是顾名思义BeanDefinitionRegistryPostProcessor在BeanFactoryPostProcessor基础上增加了BeanDefinitionRegistry的功能。

从这一点入手即可知道@Bean、@ComponentScan、@Import配置的bean就是在执行所有的BeanFactoryPostProcessor这一步骤装配的,调用流程如下。
在这里插入图片描述

在实际执行BeanFactoryPostProcessor时,spring容器将具体实现委托给了PostProcessorRegistrationDelegate这个工具类。PostProcessorRegistrationDelegate代码中处理BeanFactoryPostProcessord的代码如下

PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors

public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List beanFactoryPostProcessors) {Set processedBeans = new HashSet<>();if (beanFactory instanceof BeanDefinitionRegistry) {BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;List regularPostProcessors = new ArrayList<>();List registryProcessors = new ArrayList<>();//----------遍历spring容器当前已有的beanFactoryPostProcessors---------//for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {BeanDefinitionRegistryPostProcessor registryProcessor =(BeanDefinitionRegistryPostProcessor) postProcessor;registryProcessor.postProcessBeanDefinitionRegistry(registry);registryProcessors.add(registryProcessor);}else {regularPostProcessors.add(postProcessor);}}//-----------执行已注册的 BeanDefinitionRegistryPostProcessor bean--------------//List currentRegistryProcessors = new ArrayList<>();//postProcessBeanDefinitionRegistry()方法//首先先执行实现了PriorityOrdered接口的BeanDefinitionRegistryPostProcessorString[] postProcessorNames =beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);for (String ppName : postProcessorNames) {if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);}}sortPostProcessors(currentRegistryProcessors, beanFactory);registryProcessors.addAll(currentRegistryProcessors);invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());currentRegistryProcessors.clear();//然后执行实现了Ordered接口的BeanDefinitionRegistryPostProcessorpostProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);for (String ppName : postProcessorNames) {if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);}}sortPostProcessors(currentRegistryProcessors, beanFactory);registryProcessors.addAll(currentRegistryProcessors);invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());currentRegistryProcessors.clear();//最后执行其他未被扫描到的BeanDefinitionRegistryPostProcessor//	因为处理的过程中可能会注册新的BeanDefinitionRegistryPostProcessor//	所以这里用循环确保所有的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();}// postProcessBeanFactory()方法invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);}else {//没有实现BeanDefinitionRegistry接口则直接执行执行BeanFactoryPostProcessorinvokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);}//--------------------------执行已注册的 BeanFactoryPostProcessor bean------------------------------//String[] postProcessorNames =beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);// 跟上面一样// 都是先按 实现了PriorityOrdered接口、实现了Ordered接口、其他 的顺序处理 BeanFactoryPostProcessorList priorityOrderedPostProcessors = new ArrayList<>();List orderedPostProcessorNames = new ArrayList<>();List nonOrderedPostProcessorNames = new ArrayList<>();for (String ppName : postProcessorNames) {if (processedBeans.contains(ppName)) {// 跳过已经执行的BeanFactoryPostProcessor}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);}}sortPostProcessors(priorityOrderedPostProcessors, beanFactory);invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);List orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());for (String postProcessorName : orderedPostProcessorNames) {orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));}sortPostProcessors(orderedPostProcessors, beanFactory);invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);List nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());for (String postProcessorName : nonOrderedPostProcessorNames) {nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));}invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);beanFactory.clearMetadataCache();}

这个方法首先会判断beanFactory是否来自BeanDefinitionRegistry,如果不是则直接执行beanFactory.beanFactoryPostProcessors属性指向的容器本身已有的BeanFactoryPostProcessors,如果是则保证先执行所有的BeanDefinitionRegistryPostProcessor(包括BeanDefinition中注册的)后再执行BeanFactoryPostProcessors(包括BeanDefinition中注册的)。两者的执行都按 本身已有的->BeanDefinition中PriorityOrdered修饰的->BeanDefinition中Ordered修饰的->BeanDefinition中其他未被执行的顺序执行

ConfigurationClassPostProcessor的注册

上面展示了spring容器在启动的过程中是如何执行BeanFactoryPostProcessors的。那么问题来了,ConfigurationClassPostProcessor这个BeanFactoryPostProcessors是spring容器自带的还是BeanDefinition中注册的呢?如果是注册的,那是何时注册的呢?
我们首先排除容器自带的,通过debug代码可以发现当执行invokeBeanFactoryPostProcessors方法时,spring容器自带的BeanFactoryPostProcessors即传进来的beanFactoryPostProcessors参数为空。
在这里插入图片描述
既然不是自带的BeanFactoryPostProcessors那就肯定在前面的某一步中,注册了ConfigurationClassPostProcessor这么一个BeanDefinition。
通过debug代码分析可以得知,在执行refresh方法前(甚至在register方法执行前)就已经存在beanName为org.springframework.context.annotation.internalConfigurationAnnotationProcessor的ConfigurationClassPostProcessor bean了。由此可以推断是在AnnotationConfigApplicationContext容器初始化的时候注册的。
在这里插入图片描述
查看初始化流程,可以发现创建reader时会执行AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry)
在这里插入图片描述
AnnotationConfigUtils.registerAnnotationConfigProcessors中会默认注册一些beanDefinition,ConfigurationClassPostProcessor就是在这里注册的
在这里插入图片描述


如何装配

主流程

接下来看ConfigurationClassPostProcessor的具体注册beanDefinition的逻辑
ConfigurationClassPostProcessor#registerAnnotationConfigProcessors

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {List configCandidates = new ArrayList<>();String[] candidateNames = registry.getBeanDefinitionNames();// 遍历 BeanDefinition 找到所有的 Configuration 配置类for (String beanName : candidateNames) {BeanDefinition beanDef = registry.getBeanDefinition(beanName);// 如果CONFIGURATION_CLASS_ATTRIBUTE属性不为空说明已经处理过了,打印日志if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {if (logger.isDebugEnabled()) {logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);}}else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));}}// 没有配置类直接返回if (configCandidates.isEmpty()) {return;}// 配置类按order注解排序configCandidates.sort((bd1, bd2) -> {int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());return Integer.compare(i1, i2);});// beanName生成器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();}// 解析 @Configuration class 并注册解析到的beanConfigurationClassParser parser = new ConfigurationClassParser(this.metadataReaderFactory, this.problemReporter, this.environment,this.resourceLoader, this.componentScanBeanNameGenerator, registry);Set candidates = new LinkedHashSet<>(configCandidates);Set alreadyParsed = new HashSet<>(configCandidates.size());do {StartupStep processConfig = this.applicationStartup.start("spring.context.config-classes.parse");// 解析Configuration配置类parser.parse(candidates);parser.validate();Set configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());configClasses.removeAll(alreadyParsed);if (this.reader == null) {this.reader = new ConfigurationClassBeanDefinitionReader(registry, this.sourceExtractor, this.resourceLoader, this.environment,this.importBeanNameGenerator, parser.getImportRegistry());}// 注册configurationClass 配置的beanthis.reader.loadBeanDefinitions(configClasses);alreadyParsed.addAll(configClasses);processConfig.tag("classCount", () -> String.valueOf(configClasses.size())).end();// 找出新注册的BeanDefinition再次进入循环candidates.clear();if (registry.getBeanDefinitionCount() > candidateNames.length) {String[] newCandidateNames = registry.getBeanDefinitionNames();Set oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));Set alreadyParsedClasses = new HashSet<>();for (ConfigurationClass configurationClass : alreadyParsed) {alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());}for (String candidateName : newCandidateNames) {if (!oldCandidateNames.contains(candidateName)) {BeanDefinition bd = registry.getBeanDefinition(candidateName);if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&!alreadyParsedClasses.contains(bd.getBeanClassName())) {candidates.add(new BeanDefinitionHolder(bd, candidateName));}}}candidateNames = newCandidateNames;}}while (!candidates.isEmpty());if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());}if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();}}

说通俗一点就是
1:找到所有配置类
2:解析配置类
3:加载配置类配置的beanDefinition
4:循环23直至没有新的配置类加载

解析配置类

点进去parser.parse(candidates)
在这里插入图片描述
最终会来到ConfigurationClassParser#doProcessConfigurationClass

protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass, Predicate filter)throws IOException {if (configClass.getMetadata().isAnnotated(Component.class.getName())) {// 解析成员类processMemberClasses(configClass, sourceClass, filter);}// 解析 @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");}}// 解析 @ComponentScan 注解Set componentScans = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);if (!componentScans.isEmpty() &&!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {for (AnnotationAttributes componentScan : componentScans) {//最终会调用ClassPathBeanDefinitionScanner.doScan()方法实现beanDefinition的注册Set scannedBeanDefinitions =this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());for (BeanDefinitionHolder holder : scannedBeanDefinitions) {BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();if (bdCand == null) {bdCand = holder.getBeanDefinition();}if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {parse(bdCand.getBeanClassName(), holder.getBeanName());}}}}// 解析 @Import 注解processImports(configClass, sourceClass, getImports(sourceClass), filter, true);// 解析 @ImportResource 注解AnnotationAttributes importResource =AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);if (importResource != null) {String[] resources = importResource.getStringArray("locations");Class readerClass = importResource.getClass("reader");for (String resource : resources) {String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);configClass.addImportedResource(resolvedResource, readerClass);}}// 解析 @Bean 注解(与@Component不同的是这里不会立即注册到beanDefinitionMap中,是在后续的loadBeanDefinition方法才注册)Set beanMethods = retrieveBeanMethodMetadata(sourceClass);for (MethodMetadata methodMetadata : beanMethods) {configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));}// 递归接口的默认实现processInterfaces(configClass, 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);return sourceClass.getSuperClass();}}return null;}

在这一步会解析配置类的 成员类、@PropertySource、@ComponentScan、@Import、@ImportResource、@Bean 以及递归接口默认实现和递归父类,将解析到的结果封装成ConfigurationClass保存到parse.configurationClasses属性,然后再调用reader.loadBeanDefinitions(configClasses)方法实现beanDefintion的加载。

需要注意的是@ComponentScan会在解析这一步的时先将对应的beanDefinition注册到map中了,而@Import、@Bean注解的beanDefinition是在后续的loadBeanDefinitions才注册到map中的。

加载配置类配置的beanDefinition

ConfigurationClassBeanDefinitionReader#loadBeanDefinitions
在这里插入图片描述
可以看到,@Import和@Bean配置的bean都在这一步注册了。

上图提到了两次@Import注解,但作用是不一样的。第一次如果这个类是被Import进来的则先注册他自身,第二次是注册他Import过来类。不过这一步最主要也是最常用的还是注册了@Bean注解的bean。

总结

在启动AnnotationConfigApplicationContext容器创建reader时会默认注册一些beanDefinition,其中就包括ConfigurationClassPostProcessor。ConfigurationClassPostProcessor又是一个beanFactoryPostProcessor,所以后续refresh中invokeBeanFactoryPostProcessors方法执行所有BeanFactoryPostProcessor的方法时就会调用ConfigurationClassPostProcessor的相关逻辑实现@Bean、@ComponentScan、@Import配置的bean的装配。
实现大致如下
1:找到所有配置类
2:解析配置类(@ComponentScan在这一步注册)
3:加载配置类配置的beanDefinition(@Import,@Bean在这一步注册)
4:循环23直至没有新的配置类加载
最后的最后
@ComponentScan调用ClassPathBeanDefinitionScanner.doScan()
@Bean调用BeanDefinitionRegistry.registerBeanDefinition()
@Import调用ImportBeanDefinitionRegistrar.registerBeanDefinitions()
实现beanDefinition的注册。

相关内容

热门资讯

谁能给我发几个好看的穿越文,女... 谁能给我发几个好看的穿越文,女主要聪明点的,还有请给我发下《蛇蝎皇后》这篇小说我有比较多的小说,但是...
网络语叫粉丝是什么意思? 网络语叫粉丝是什么意思?'粉丝’是英语‘Fans’(狂热、热爱之意,后引申为影迷、追星等意思)的音译...
你们希望柯南的最后大结局是新兰... 你们希望柯南的最后大结局是新兰永恒吗肯定滴啊,如果新兰都不永恒了谁还相信爱情、、、 上次预告还有五年...
出师表朗诵 出师表朗诵出师表的朗诵应该配上什么音乐,或者歌曲(最好是现代的),给点建议!新三国片头曲吧试试王宗贤...
《率土之滨》平民新手开局怎么玩... 《率土之滨》平民新手开局怎么玩?前期开荒核心是完美的利用每一点资源,把他变为你前期最有利的抢地武器!...
咒怨里面的白老妇[那个鬼 的扮... 咒怨里面的白老妇[那个鬼 的扮演者是谁?告诉我吧求求你们了 我要是不知道他是活人演的拿篮球的那个老婆...
体验当家的辛苦 体验当家的辛苦自己体会会有灵感的。什么事情还是自己做一下比较真实这样的作文就必须要自己去亲身体会,让...
(只要人物时间地点的正确就能开... (只要人物时间地点的正确就能开启尘封已久的记忆)能解释一下这个是什么含义是一个女的写给我的是表白吗大...
科学和迷信你们信哪个?不能解释... 科学和迷信你们信哪个?不能解释的东西事物算得上是迷信吗迷信我是不会相信的,如果对所谓的科学百分之百的...
请问延世大学韩语教程和标准韩国... 请问延世大学韩语教程和标准韩国语哪本更适合自学?哪本语法更详细,更易于学习。先谢谢啦。你好,标准韩国...
有谁曾经暗恋一个人,很久都没有... 有谁曾经暗恋一个人,很久都没有见到却还是很想念他想就想呗,随自己的意就可以了让她留在心里吧.我也曾暗...
昨天在车上看的碟子,好像是,一... 昨天在车上看的碟子,好像是,一个DJ现场,一个人边唱边喝酒,还互动问题,答完就喝。提问的歌曲有:洪湖...
魔兽世界小白任务和战场问题 魔兽世界小白任务和战场问题去魔兽数据库里找 多玩 嘟牛 这两个网站的 数据库很全 什么任务...
《公主回宫》什么时候开播? 《公主回宫》什么时候开播?已经开播了,祝你愉快.
到底大灰狼和小绵羊是一对,还是... 到底大灰狼和小绵羊是一对,还是和小白兔是一对很显然小绵羊和小白兔是一对
你觉着《他来了请闭眼》中霍建华... 你觉着《他来了请闭眼》中霍建华演技如何?《他来了请闭眼》中霍建华演技很好。霍建华的演技很好,能够表现...
九色神鹿故事? 九色神鹿故事?很久以前,在恒河边上有一只九种毛色的鹿,它那闪闪发光的鲜艳毛色和洁白如雪的美丽鹿角,以...
刘州成坚强的故事 刘州成坚强的故事就是男子汉一点的 刘小美的刘州成他是一个很坚强的人来的.. 一路走来他都是勇敢地走来...
书籍设计的内容简介 书籍设计的内容简介《书籍设计》立足于新世纪中国艺术教育的改革,将艺术理论与技能培训融会贯通,从内容选...
2024年山西中考初二考地理生... 2024年山西中考初二考地理生物吗不考。截止2022年6月1日山西中考除晋中和阳泉两个改革试点区域外...