惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

小众软件
小众软件
A
About on SuperTechFans
博客园 - Franky
Engineering at Meta
Engineering at Meta
Recent Announcements
Recent Announcements
云风的 BLOG
云风的 BLOG
B
Blog
Microsoft Security Blog
Microsoft Security Blog
L
LangChain Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
U
Unit 42
Martin Fowler
Martin Fowler
Y
Y Combinator Blog
Stack Overflow Blog
Stack Overflow Blog
博客园 - 叶小钗
Vercel News
Vercel News
Apple Machine Learning Research
Apple Machine Learning Research
The Cloudflare Blog
Last Week in AI
Last Week in AI
腾讯CDC
Microsoft Azure Blog
Microsoft Azure Blog
爱范儿
爱范儿
V
V2EX
G
Google Developers Blog

博客园 - 夕阳醉了

基于 LangGraph 的AI 多Agent协作系统实战:从架构设计到并行调度 Spring扩展接口(4):InstantiationAwareBeanPostProcessor Spring扩展接口(2):BeanDefinitionRegistryPostProcessor Spring扩展接口(1):ApplicationContextInitializer Redis从入门到放弃(12):pipeline管道技术 Redis从入门到放弃(11):雪崩、击穿、穿透 Redis从入门到放弃(10):分布式锁 Redis从入门到放弃(9):集群模式 Redis从入门到放弃(8):哨兵模式 Redis从入门到放弃(7):主从复制 Redis从入门到放弃(6):持久化 Redis从入门到放弃(5):事务 Redis从入门到放弃(4):3种新数据类型 Redis从入门到放弃(3):发布与订阅 Redis从入门到放弃(2):数据类型 Redis从入门到放弃(1):安装配置 基于GPT搭建私有知识库聊天机器人(六)仿chatGPT打字机效果 基于GPT搭建私有知识库聊天机器人(五)函数调用 基于GPT搭建私有知识库聊天机器人(四)问答实现
Spring扩展接口(3):BeanFactoryPostProcessor
夕阳醉了 · 2023-10-19 · via 博客园 - 夕阳醉了

在此系列文章中,我总结了Spring几乎所有的扩展接口,以及各个扩展点的使用场景。并整理出一个bean在spring中从被加载到最终初始化的所有可扩展点的顺序调用图。这样,我们也可以看到bean是如何一步步加载到spring容器中的。


BeanFactoryPostProcessor

1、概述

public interface BeanFactoryPostProcessor {
    void postProcessBeanFactory(ConfigurableListableBeanFactory var1) throws BeansException;
}

BeanFactoryPostProcessor是Spring框架中的一个重要接口,用于在BeanFactory加载Bean定义之后、实例化Bean之前对BeanFactory进行自定义修改和扩展。它允许开发人员在Spring容器加载配置文件并创建Bean实例之前对Bean定义进行操作,例如修改属性值、添加额外的元数据等。

在应用程序启动时,Spring容器会自动检测并调用所有实现了BeanFactoryPostProcessor接口的类的postProcessBeanFactory方法。开发人员可以利用这个方法来实现自定义的逻辑,从而实现一些高级的自定义逻辑和功能扩展。

前文介绍的BeanDefinitionRegistryPostProcessor为其子接口。

2、简单案例

下面是一个示例,展示了如何实现动态的给Bean修改属性值:

public class User {
    String name;
    String password;
}

import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;

@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        BeanDefinition beanDefinition = beanFactory.getBeanDefinition("user");
        if (Objects.nonNull(beanDefinition)) {
            MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
            propertyValues.addPropertyValue("name", "张三");
            propertyValues.addPropertyValue("password", "123456");
        }
    }
}

同样,若当容器中有多个BeanFactoryPostProcessor的时候,可以通过实现PriorityOrdered或Ordered接口来指定顺序(优先执行PriorityOrdered的接口,其次是Ordered的接口,最后是没有实现任何排序的接口):

@Override
public int getOrder() {
   return 0; //值越小,优先级越高
}

3、源码分析

  • 在MyBeanFactoryPostProcessor打上断点,启动SpringApplication,可以看到左下角的调用链路。

  • spring的AbstractApplicationContext的refresh方法,执行this.invokeBeanFactoryPostProcessors(beanFactory)。

  • 接下来进入核心的invokeBeanFactoryPostProcessors方法,大概逻辑是先取出所有实现了BeanFactoryPostProcessor接口的类,在for循环中根据实现类的优先级放入不同的ArrayList()等待调用,先PriorityOrdered,再Ordered,最后调用无优先级的实现类。
  • 注意:BeanDefinitionRegistryPostProcessor也实现了BeanFactoryPostProcessor接口,所以postProcessorNames也包含BeanDefinitionRegistryPostProcessor实现类,它已先于BeanFactoryPostProcessor执行,所以在for循环中需要排除,见if (!processedBeans.contains(ppName))。

  • 最后,遍历调用BeanFactoryPostProcessor的组件