前言:BeanFactoryPostProcessor是Spring中的重要组成接口,容器创建过程中起到解析注解,注册BeanDifinition,改变BeanDefiniton属性(也就是改变bean的属性)等重要的作用。对于注解配置的Spring来说,BeanFactoryPostProcessor至关重要。

 BeanFactoryPostProcessor接口的方法:

这是一个函数式接口,只有一个方法,这个方法的参数可以得到beanFactory,就可以修改beanFactory中的内容。所有的beanDefinition已经加载完毕,但是bean还没有初始化,根据beanFactory可以修改和添加bean的属性,甚至是那些早期初始化暴露的bean(循环依赖过程会有这些bean)

@FunctionalInterface
public interface BeanFactoryPostProcessor {/**  * Modify the application context's internal bean factory after its standard* initialization. All bean definitions will have been loaded, but no beans* will have been instantiated yet. This allows for overriding or adding* properties even to eager-initializing beans.* @param beanFactory the bean factory used by the application context* @throws org.springframework.beans.BeansException in case of errors*/void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;}
接口BeanDefinitionRegistryPostProcessor继承BeanFactoryPostProcessor还多了一个方法:postProcessBeanDefinitionRegistry方法的参数是可以得到一个BeanDefinitionRegistry,利用它可以向Spring容器中注册bean,即手动向Spring容器中注册bean.

public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {/*** Modify the application context's internal bean definition registry after its* standard initialization. All regular bean definitions will have been loaded,* but no beans will have been instantiated yet. This allows for adding further* bean definitions before the next post-processing phase kicks in.* @param registry the bean definition registry used by the application context* @throws org.springframework.beans.BeansException in case of errors*/void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;}

上面两个接口就把BeanFactory后置处理器分成两类,一类是有注册功能的BeanDefinitionRegistryPostProcessor,一类是没有注册功能的:BeanFactoryPostProcessor

SpringIoc在初始化过程中会分开执行这两类后置处理器。其中很重一个后置处理器:ConfigurationClassPostProcessor

它实现了BeanDefinitionRegistryPostProcessor接口也就是它有两个功能,一个注册bean的功能,一个修改bean定义的功能。注解启动Spring的时候,它起到了很大的作用。

我们先用图宏观的看下调用过程,后面跟源码去看:

一:Ioc注册原理

Ioc整个启动初始化流程用到很多BeanFactoryPostProcessor,我整体分开看,前面必有注册,初始化的过程,注册就是bean资源注册到BeanFactory的beanDefinitonMap中,初始化就是把注册进来的bean进行填充属性。

我们以注解的方式配置Spring来看BeanFactoryPostProcessor在注册中的作用。

以注解JavaConfigure入手,来看SpringIoc是怎么创建出来的。

@ImportResource("spring-ioctest.xml")
@Configuration
@Import({ Myregister.class,MyImport.class})
public class BeanConfig {@Bean
//  @Conditional(MyConditional.class)public People people(){return new People();}
}
public class Myregister implements ImportBeanDefinitionRegistrar {public  void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
//         自定义一个BeanDifinitionRootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Bird.class);
//      利用BeanDefinition给对象赋值rootBeanDefinition.getPropertyValues().add("name","myFridBird");//     使用BeanDefinitionRegistry注册器向Spring中的 beanDefinitonMap注入beanregistry.registerBeanDefinition("myBird",rootBeanDefinition);}
}
public class MyImport implements ImportSelector {//@Overridepublic String[] selectImports(AnnotationMetadata importingClassMetadata) {
//      类的全路径名,返回的类会被Spring管理,前提是MyImport被Spring管理return new String[]{Bird.class.getName()};}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="task" class="com.my.ioc.pojo.TestTask"/>
</beans>

所用的组件就是上面的内容。

入口:使用的是高级适合注解的容器:AnnotationConfigApplicationContext

AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanConfig.class);

1:

调用AnnotationConfigApplicationContext构造函数之前会先调用其父类的构造方法创建一个DefaultListableBeanFactory,直接new出来的,作为全局的bean工厂。

:2:AnnotationConfigApplicationContext而它自身的构造函数会做如下操作:

1)this()函数执行完,beanFactory中会有五个提前注册的postProcessor: 第一个就是上面说的ConfigurationClassPostProcessor

2)第二个方法register(componentClasses);  就是把我们传递的BeanConfig类也注册进去:

3)refresh();方法要做主要的事情了。

@Overridepublic void refresh() throws BeansException, IllegalStateException {//容器启动开始 ,加锁保证只有一个线程在进行初始化synchronized (this.startupShutdownMonitor) {// Prepare this context for refreshing.//初始化配置信息prepareRefresh();// Tell the subclass to refresh the internal bean factory.//获取刷新的beanFactory//对于AnnotationConfigApplicationContext的作用来说
//           1:调用GenericApplicationContext.refreshBeanFactory 只是指定了serializationId
//          2:  直接返回beanFactory(不用创建,容器中已存在)
//          对于ClassPathXmlApplicationContext
//          1:调用AbstractRefreshableApplicationContext.refreshBeanFactory
//              如果存在beanFactory先销毁bean,关闭beanFactory再创建beanFactory
//          2:注册传入的xml配置,注册到beanFactory
//          3: 将beanFactory赋值给容器,返回beanFactoryConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// Prepare the bean factory for use in this context.//准备beang工厂,指定类的加载器,添加后置处理器,注册缺省bean等
//          beanFactory添加两个后置处理器ApplicationContextAwareProcessor,ApplicationListenerDetector(new)
//AbstractBeanFactory.beanPostProcessors中prepareBeanFactory(beanFactory);try {// Allows post-processing of the bean factory in context subclasses.//空方法,
//              允许在上下文的子类中对beanFactory进行后处理
//              比如:AbstractRefreshableApplicationContext.postProcessBeanFactorypostProcessBeanFactory(beanFactory);// Invoke factory processors registered as beans in the context.//最关键的方法//1:通过beanFactory.getBean(ppName,BeanDefinitionRegistryPostProcessor.class)拿到 ConfigurationClassPostProcessor
//               2:通过ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry注册所有注解配置的bean
//                 注册顺序:
//               @ComponentScan>实现ImportSelector>方法bean>@ImportSource>实现 ImportBeanDefinitionRegistrar(相对顺序,都在同一个配置类上)
//               3:调用ConfigurationClassPostProcessor.postProcessBeanFactory增强@Configuration修饰的配置类
//                   AppConfig==>AppConfig$$EnhancerBySpringCGLIB
//                  可以处理内部方法bean之间的调用防止多例,
//                添加了后置处理器ConfigurationClassPostProcessor.ImportAwareBeanPostProcess(new)invokeBeanFactoryPostProcessors(beanFactory);// Register bean processors that intercept bean creation.//注册拦截bean创建的后置处理器//1:添加Spring自身的:BeanPostProcessorChecker以及注册了beanDefinitionn的两个
//                   CommonAnnotationBeanPostProcessor ,AutowiredAnnotationBeanPostProcessor
//              重新添加ApplicationListenerDetector(new)删除旧的,移除到处理器链末尾
//              2:用户自定义的后置处理器
//              注册了beanDefinition的会通过beanFactory.getBean(ppName,BeanPostProcessor.class)获取后置处理器registerBeanPostProcessors(beanFactory);// Initialize message source for this context.//initMessageSource();// Initialize event multicaster for this context.//初始化事件多播器initApplicationEventMulticaster();// Initialize other special beans in specific context subclasses.////onRefresh();// Check for listener beans and register them.////registerListeners();// Instantiate all remaining (non-lazy-init) singletons.////finishBeanFactoryInitialization(beanFactory);// Last step: publish corresponding event.//finishRefresh();}

2:配置解析

我们主要看invokeBeanFactoryPostProcessors(beanFactory);方法了。根据方法名我们就可以知道,这个方法里面执行BeanFactoryPostProcessors的。

 protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
//      getBeanFactoryPostProcessors() 拿到当前应用上下文beanFactoryPostProcessors,直接返回的this.beanFactoryPostProcessors
//      invokeBeanFactoryPostProcessors: 实例化并调用所有已经注册的BeanFactoryPostProcessorPostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));}}

这次执行  this.beanFactoryPostProcessors 里面没有数据

接下来看:

PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors:

第一行注释就写着:先执行BeanDefinitionRegistryPostProcessors。   因为具有注册功能。for循环不会执行。

紧接着会得到将要执行的BeanDefinitionRegistryPostProcessor,根据类型获取:beanFactory.getBeanNamesForType,这里postProcessorNames数组只有一个值:org.springframework.context.annotation.internalConfigurationAnnotationProcessor,它对应的Class是:ConfigurationClassPostProcessor

然后根据排序方式进行排序后执行:

我们看下:invokeBeanDefinitionRegistryPostProcessors方法:

就是遍历循环,执行:postProcessor.postProcessBeanDefinitionRegistry(registry);注册功能。

我们看下:ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry

进入:processConfigBeanDefinitions(BeanDefinitionRegistry registry);

当前流程会走到:ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory),来找到@Configuration类,我们看下怎么判断的:

只有我们我们的BeanConfig类的BeanDefinition才满足条件:

BeanDefinition中的className属性并不是所有的bean都有这个属性值的,比如我们实现FactoryBean来注入的Bean。

上面的方法执行过后没有返回,就可能是个带有注解的需要解析的类。下面就是具体的判断:

带有@Configuration的配置类的BeanDefinition的属性中的:org.springframework.context.annotation.ConfigurationClassPostProcessor.configurationClass属性会被设置为"full"。其它注解的类的BeanDefinition这个属性设置为"lite".

我们的BeanConfig的className当前还是它自身,但是这个full属性设置之后,后面这个className会变成一个BeanConfig的动态代理。

执行完check之后configCandidates中有我们的BeanConfig的BeanDefinition

得到所有的@Configuration注解类,然后就可以解析这个配置类,会先定义一个parser:

主要在ConfigurationClassParser#parse方法中:

封装了一个ConfigurationClass专门代表我们的配置类:

然后处理其它注解:

在处理processImports方法的时候,处理ImportSelector,ImportBeanDefinitionRegistrar接口实现的接口。

解析完注解之后会把一些注解配置类注册到BeanFactory中,因为有些注解类在解析的时候并没有直接放入容器中:


回到PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors方法中:

会再次根据Ordered注解的类进行执行

上面执行的是后置处理器注册的功能的方法postProcessBeanDefinitionRegistry,后置处理器还有一个不是注册功能的方法postProcessBeanFactory

会去调用ConfigurationClassPostProcessor的postProcessBeanFactory

在enhanceConfigurationClasses方法中把我们的BeanConfig的BeanDefinition的className属性值替换为CGLib的代理类:

public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
//      需要被增强的BeanDefinitionMap<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();for (String beanName : beanFactory.getBeanDefinitionNames()) {BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
//          得到ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE的属性值,上面讲过如果是Configuration注解类默认使用代理方法则是fullObject configClassAttr = beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE);MethodMetadata methodMetadata = null;if (beanDef instanceof AnnotatedBeanDefinition) {methodMetadata = ((AnnotatedBeanDefinition) beanDef).getFactoryMethodMetadata();}if ((configClassAttr != null || methodMetadata != null) && beanDef instanceof AbstractBeanDefinition) {// Configuration class (full or lite) or a configuration-derived @Bean method// -> resolve bean class at this point...AbstractBeanDefinition abd = (AbstractBeanDefinition) beanDef;if (!abd.hasBeanClass()) {try {abd.resolveBeanClass(this.beanClassLoader);}catch (Throwable ex) {throw new IllegalStateException("Cannot load configuration class: " + beanDef.getBeanClassName(), ex);}}}
//          把需要增强的Configureation 放入configBeanDefsif (ConfigurationClassUtils.CONFIGURATION_CLASS_FULL.equals(configClassAttr)) {if (!(beanDef instanceof AbstractBeanDefinition)) {throw new BeanDefinitionStoreException("Cannot enhance @Configuration bean definition '" +beanName + "' since it is not stored in an AbstractBeanDefinition subclass");}else if (logger.isInfoEnabled() && beanFactory.containsSingleton(beanName)) {logger.info("Cannot enhance @Configuration bean definition '" + beanName +"' since its singleton instance has been created too early. The typical cause " +"is a non-static @Bean method with a BeanDefinitionRegistryPostProcessor " +"return type: Consider declaring such methods as 'static'.");}configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);}}if (configBeanDefs.isEmpty()) {// nothing to enhance -> return immediatelyreturn;}
//遍历configBeanDefs进行增强,然后替换BeanDefinition.setBeanClass 为代理后的值ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();for (Map.Entry<String, AbstractBeanDefinition> entry : configBeanDefs.entrySet()) {AbstractBeanDefinition beanDef = entry.getValue();// If a @Configuration class gets proxied, always proxy the target classbeanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);// Set enhanced subclass of the user-specified bean classClass<?> configClass = beanDef.getBeanClass();Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);if (configClass != enhancedClass) {if (logger.isTraceEnabled()) {logger.trace(String.format("Replacing bean definition '%s' existing class '%s' with " +"enhanced class '%s'", entry.getKey(), configClass.getName(), enhancedClass.getName()));}
//              重新赋值beanDef.setBeanClass(enhancedClass);}}}

执行完这个方法后,我们看BeanConfig的BeanDefinition的beanClass已经改变了:

后面是根据BeanFactoryPostProcessor类型来获取一些后置处理器,然后进行调用,过程和上面BeanDefinitionRegistryPostProcessor过程类似,但是由于BeanDefinitionRegistryPostProcessor继承BeanFactoryPostProcessor,所以可能会有重复,所以会有一跳过已经执行过。

后面这个执行完我们BeanFactoryPostProcessor才算结束。

这时候我们的容器里面已经有了我们业务Bean和一些扩展注册的bean了。

下一步就是要注册beanPostProcessor了。我们上一步只是注册可还没有把bean进行初始化,属性注入,循环依赖问题等都都没解决呢,下一篇文章再说:

Spring源码分析(二)BeanFactoryPostProcessor之ConfigurationClassPostProcessor的调用过程相关推荐

  1. Spring源码分析之Bean的创建过程详解

    前文传送门: Spring源码分析之预启动流程 Spring源码分析之BeanFactory体系结构 Spring源码分析之BeanFactoryPostProcessor调用过程详解 本文内容: 在 ...

  2. Spring源码分析(三)

    Spring源码分析 第三章 手写Ioc和Aop 文章目录 Spring源码分析 前言 一.模拟业务场景 (一) 功能介绍 (二) 关键功能代码 (三) 问题分析 二.使用ioc和aop重构 (一) ...

  3. Spring源码分析——汇总全集

    文章目录 一.背景 二.源码分析目录 三.源码番外篇(补充) 更新时间 更新内容 备注 2022-04-01 Spring源码分析目录和计划 2022-04-10 Spring源码分析一:容器篇-re ...

  4. Spring 源码分析衍生篇十 :Last-Modified 缓存机制

    文章目录 一.前言 二.Last-Modify 三.实现方案 1. 实现 org.springframework.web.servlet.mvc.LastModified接口 1.1. 简单演示 1. ...

  5. Spring 源码分析(四) ——MVC(二)概述

    随时随地技术实战干货,获取项目源码.学习资料,请关注源代码社区公众号(ydmsq666) from:Spring 源码分析(四) --MVC(二)概述 - 水门-kay的个人页面 - OSCHINA ...

  6. 【spring源码分析】IOC容器初始化(二)

    前言:在[spring源码分析]IOC容器初始化(一)文末中已经提出loadBeanDefinitions(DefaultListableBeanFactory)的重要性,本文将以此为切入点继续分析. ...

  7. Spring源码分析八:Mybatis ORM映射框架原理

    文章目录 (一)Mybatis单独操作数据库程序 1.1.数据库表 1.2.建立PO 1.3.建立mapper接口映射 1.4.建立Mybatis配置文件 1.5.建立mapper映射文件 1.6.测 ...

  8. Spring 源码分析衍生篇十三 :事务扩展机制 TransactionSynchronization

    文章目录 一.前言 二.TransactionSynchronization 1. TransactionSynchronization 1.1 TransactionSynchronization ...

  9. 【四】Spring源码分析之启动主流程---AbstractApplicationContext的refresh方法

    入口: 在SpringBoot启动的时候,SpringApplication的run方法中 refreshContext(context); 里面最终调用的是AbstractApplicationCo ...

  10. spring源码分析之spring-core总结篇

    1.spring-core概览 spring-core是spring框架的基石,它为spring框架提供了基础的支持. spring-core从源码上看,分为6个package,分别是asm,cgli ...

最新文章

  1. 基于Python查找图像中最常见的颜色
  2. python列表推导式实现从1加到100_python之生成器和列表推导式
  3. request用法_Go 语言 Web 应用开发 第 04 课:高级模板用法
  4. 新一代大数据处理引擎 Apache Flink
  5. Nuxt使用高德地图
  6. Win11怎么打开以前的word文档
  7. 作者:董诚,华中科技大学计算机科学与技术学院硕士生。
  8. Hibernate SQL 方言(hibernate.dialect)
  9. 破解锐捷--实现路由器认证锐捷,轻松开WiFi
  10. bat批处理命令大全(翻译转载)
  11. 空间矢量脉冲宽度调制(SVPWM)Simulink仿真教程
  12. soundpool android,android – 如何获取Soundpool的持续时间
  13. 小米手机自带计算机不能用怎么解决,如果小米手机无法进入系统怎么办?
  14. FastAdmin遇到的坑
  15. 人工智能的起源及发展
  16. PDF文件中如何插入页面?分享一个实用小妙招
  17. 详细讲解 —— 网络编程套接字(Java EE初阶)
  18. Longhorn时代,浏览器的终结?——关于Avalon和XAML
  19. Java编程:Integer的取值范围(-2^31~2^31-1)分析
  20. USBCNC ATC自动换刀教程

热门文章

  1. js图片轮播效果实现代码
  2. 微信小程序开发部署上线流程
  3. js复制文本(带文本格式or不带文本格式)
  4. Pytorch的rand、randn和normal的用法及区别
  5. 本地调试公众号微信登录,微信支付
  6. opencv对视频进行人脸识别--使用videoCapture类
  7. 手把手 Golang 实现静态图像与视频流人脸识别
  8. 使用虹软SDK进行视频人脸识别
  9. android midi字节,MIDI的20个基本概念
  10. 多周期时间序列分解算法——MSTL原理