Spring的BeanFactoryPostProcessor接口

Easter79
• 阅读 774

接口简介

BeanFactoryPostProcessor 接口是 Spring 初始化 BeanFactory 时对外暴露的扩展点,Spring IoC 容器允许 BeanFactoryPostProcessor 在容器实例化任何 bean 之前读取 bean 的定义,并可以修改它。

BeanDefinitionRegistryPostProcessor 继承自 BeanFactoryPostProcessor,比 BeanFactoryPostProcessor 具有更高的优先级,主要用来在常规的 BeanFactoryPostProcessor 检测开始之前注册其他 bean 定义。特别是,你可以通过 BeanDefinitionRegistryPostProcessor 来注册一些常规的 BeanFactoryPostProcessor,因为此时所有常规的 BeanFactoryPostProcessor 都还没开始被处理。

Spring的BeanFactoryPostProcessor接口

注意点:通过BeanDefinitionRegistryPostProcessor 注册的 BeanDefinitionRegistryPostProcessor 接口的postProcessBeanDefinitionRegistry方法将得不到调用,具体的原因会在下面的代码中解释。

BeanFactoryPostProcessor 接口调用机制

BeanFactoryPostProcessor 接口的调用在 AbstractApplicationContext#invokeBeanFactoryPostProcessors方法中。

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {        PostProcessorRegistrationDelegate.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()));        }    }

进入PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors())方法:

public static void invokeBeanFactoryPostProcessors(            ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {   // 用于存放已经处理过的Bean名字        Set<String> processedBeans = new HashSet<>();   // 一般会进入这个判断        if (beanFactory instanceof BeanDefinitionRegistry) {            BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;    // 所谓的regularPostProcessors就是指实现BeanFactoryPostProcessor接口的Bean            List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();    // 所谓的registryProcessors就是指实现BeanDefinitionRegistryPostProcessor接口的Bean            List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();    // 这边遍历的是通过ApplicationContext接口注册的BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor接口    // 需要和BeanFactory中BeanDefinitionMap中的BeanFactoryPostProcessor接口区分开            for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {                if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {                    BeanDefinitionRegistryPostProcessor registryProcessor =                            (BeanDefinitionRegistryPostProcessor) postProcessor;      //如果是BeanDefinitionRegistryPostProcessor,则先进行postProcessBeanDefinitionRegistry处理,这个方法一般进行BeanDefinition注册,从这边可以看出BeanDefinitionRegistryPostProcessor接口的方法先调用,所以优先级高于BeanFactoryPostProcessor      // 通过这个代码可以看出,通过ApplicationContext直接注册的BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor并不支持Order接口,而是根据注册的顺序执行                    registryProcessor.postProcessBeanDefinitionRegistry(registry);      // 保存这个BeanDefinitionRegistryPostProcessor,因为还要执行这个类的BeanFactoryPostProcessor方法;                    registryProcessors.add(registryProcessor);                }                else {      // 保存,后面还要执行这个类的BeanFactoryPostProcessor方法;                    regularPostProcessors.add(postProcessor);                }            }            List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();    // 这边获取的是BeanFactory中的BeanDefinitionRegistryPostProcessor            String[] postProcessorNames =                    beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);            for (String ppName : postProcessorNames) {     //先处理PriorityOrdered标注的BeanDefinitionRegistryPostProcessor                if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {                    currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));      //将其标记为已经处理,防止重复处理                    processedBeans.add(ppName);                }            }    // 将其排序,以便按顺序处理            sortPostProcessors(currentRegistryProcessors, beanFactory);    // 将其保存,以便处理这个类的BeanFactoryPostProcessor方法            registryProcessors.addAll(currentRegistryProcessors);    // 执行BeanDefinitionRegistryPostProcessor接口方法            invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);    // 清除,以便开始处理@Order标注的注解            currentRegistryProcessors.clear();     // 注意:这边重新获取BeanDefinitionRegistryPostProcessor是有深意的,因为上面在处理@PriorityOrdered标注的BeanDefinitionRegistryPostProcessor时可能又注入了新的BeanDefinitionRegistryPostProcessor。            postProcessorNames = 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);                }            }            sortPostProcesso.........
点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Stella981 Stella981
3年前
Spring 的 IOC 容器
一.BeanFactory 1\.在spring中,最基本的IOC容器接口是BeanFactory这个接口为具体的IOC容器的实现做了最基本的功能规定。  2\.在BeanFactory只对IOC容器的基本行为做了定义,根本不关心你的bean是怎样定义怎样加载的;XmlBeanFactory就是针对最
Easter79 Easter79
3年前
Spring高级进阶:BeanFactoryPostProcessor
BeanFactoryPostProcessor是实现spring容器功能扩展的重要接口,例如修改bean属性值,实现bean动态代理等。很多框架都是通过此接口实现对spring容器的扩展,例如mybatis与spring集成时,只定义了mapper接口,无实现类,但spring却可以完成自动注入,是不是很神奇?本文将通过简单的例子,展现BeanFacto
Easter79 Easter79
3年前
Spring高级应用之注入嵌套Bean
在Spring中,如果某个Bean所依赖的Bean不想被Spring容器直接访问,可以使用嵌套Bean。和普通的Bean一样,使用<bean元素来定义嵌套的Bean,嵌套Bean只对它的外部的Bean有效,Spring容器无法直接访问嵌套的Bean,因此定义嵌套Bean也无需指定id属性。如下配置片段是一个嵌套Bean的示例:<bean id
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
10个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这
Easter79
Easter79
Lv1
今生可爱与温柔,每一样都不能少。
文章
2.8k
粉丝
5
获赞
1.2k