Spring的bean工厂后处理器和Bean后处理器

Spring的bean工厂后处理器和Bean后处理器

一、基本原理

1.1原理一

Spring 的后处理器是 Spring 对外开发的重要扩展点,允许我们介入到 Bean 的整个实例化流程中来,以达到动态注册

BeanDefinition,动态修改 BeanDefinition,以及动态修改 Bean 的作用。Spring 主要有两种后处理器:

  • BeanFactoryPostProcessor:Bean 工厂后处理器,在 BeanDefinitionMap 填充完毕,Bean 实例化之前执行;

  • BeanPostProcessor:Bean后处理器,一般在Bean实例化之后,填充到单例池 singletonObjects之前执行。

1.2原理二

BeanFactoryPostProcessor 是一个接口规范,实现了该接口的类只要交由 Spring 容器管理的话,那么 Spring 就会回调该接口的方法,用于对 BeanDefinition 注册和修改的功能。

java 复制代码
public interface BeanFactoryPostProcessor {
    void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory);
}

二、实验

2.1验证原理二

先定义一个类然后实现接口BeanFactoryPostProcessor,重写其方法postProcessBeanFactory

java 复制代码
package com.itheima.processor;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;

public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        System.out.println("BeanFactoryMap填充完毕,回调改方法");
    }
}

将这个类在applicationContext.xml文件中配置成为bean:

java 复制代码
<bean class="com.itheima.processor.MyBeanFactoryPostProcessor"></bean>

结果:

综上所述,原理二得证。

2.2实验二通过ConfigurableListableBeanFactory获取到BeanDefinition,然后修改权限名

java 复制代码
package com.itheima.processor;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;

public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        System.out.println("BeanFactoryMap填充完毕,回调改方法");
        BeanDefinition beanDefinition = configurableListableBeanFactory.getBeanDefinition("userService");
//        修改全限制名
        beanDefinition.setBeanClassName("com.itheima.service.impl.UserServiceImpl2");
    }
}

结果:

2.3实验三使用BeanFactoryPostProcessor来添加BeanDefinition

上一个实验我们通过BeanDefinition实现了修改全限定名,那么本实验将实现添加全限制定名,通过前面的学习我们可以知道xml中的bean标签实际上是封装在一个BeanDefinition中的,然后又将BeanDefinition封装成一个map,使用时就直接遍历这个map,然后通过反射,最终是创建到单例池当的map中,调用getBean方法时则最终从该 Map 集合中取出 Bean 实例对象返回。详细可以看我的这篇博文https://blog.csdn.net/2301_80749359/article/details/157357240?fromshare=blogdetail&sharetype=blogdetail&sharerId=157357240&sharerefer=PC&sharesource=2301_80749359&sharefrom=from_link。

那么有添加全限定名,我们就需要创建一个BeanDefinition,下面是BeanDefinition的继承体系(选中BeanDefinition,按ctrl+h可以查看):

在开发过程中我们一般是使用RootBeanDefinition,所以直接new一个,然后再为其设置全限定名:

java 复制代码
        BeanDefinition beanDefinition = new RootBeanDefinition();
        beanDefinition.setBeanClassName("com.itheima.dao.impl.personDaoImpl");

当有了BeanDefinition还不够,按照流程我们还要将其放到BeanDefinition的map中,如果直接运行我们会发现报错:

当然从错误信息我们不难发现是一个叫DefaultListableBeanFactory的类再调用getbean方法,这启发我们使用DefaultListableBeanFactory来进行注册BeanDefinition,而目前我们只有ConfigurableListableBeanFactory,所以考虑将其强转为它的子类,然后进行注册BeanDefinition到BeanDefinition的map中。

java 复制代码
DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) configurableListableBeanFactory;
        defaultListableBeanFactory.registerBeanDefinition("personDao",beanDefinition);
        System.out.println(beanDefinition);

增加完毕,撒花

2.4实验四使用BeanDefinitionRegistryPostProcessor来添加BeanDefinition

BeanDefinitionRegistryPostProcessor是BeanFactoryPostProcessor的一个子类,自带注册BeanDefinition的方法,即:postProcessBeanDefinitionRegistry中的registerBeanDefinition,不需要进行强转,更为常用,具体实现如下:

1.先创建一个类来实现BeanDefinitionRegistryPostProcessor,并且是创建beanDefinition,设置全限制名(同上),然后调用registerBeanDefinition即可:

java 复制代码
package com.itheima.processor;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.RootBeanDefinition;

public class MyBeanDefinitionRegisterPostProcessor implements BeanDefinitionRegistryPostProcessor{
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
//   直接使用子类的方法来注册beanDefinition
        BeanDefinition beanDefinition = new RootBeanDefinition();
        beanDefinition.setBeanClassName("com.itheima.dao.impl.personDaoImpl");
        beanDefinitionRegistry.registerBeanDefinition("personDao",beanDefinition);
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
    }
}

2.在applicationContext.xml注册实现类: MyBeanDefinitionRegisterPostProcessor,这样Spring就会自动调用它的接口和方法了:

java 复制代码
    <bean class="com.itheima.processor.MyBeanDefinitionRegisterPostProcessor"></bean>

结果如下:

当然我们还可以看BeanDefinitionRegistryPostProcessor中的postProcessBeanDefinitionRegistry、postProcessBeanFactory和BeanFactoryPostProcessor中的postProcessBeanFactory的执行顺序:

java 复制代码
package com.itheima.processor;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.RootBeanDefinition;

public class MyBeanDefinitionRegisterPostProcessor implements BeanDefinitionRegistryPostProcessor{
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
//   直接使用子类的方法来注册beanDefinition
        BeanDefinition beanDefinition = new RootBeanDefinition();
        beanDefinition.setBeanClassName("com.itheima.dao.impl.personDaoImpl");
        beanDefinitionRegistry.registerBeanDefinition("personDao",beanDefinition);
        System.out.println("MyBeanDefinitionRegisterPostProcessor的postProcessBeanDefinitionRegistry方法执行了");
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        System.out.println("MyBeanDefinitionRegisterPostProcessor的postProcessBeanFactory方法执行了");
    }
}
java 复制代码
package com.itheima.processor;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;

public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        System.out.println("MyBeanFactoryPostProcessor的postProcessBeanFactory执行了");
    }
}

结果如下:

整个流程可以总结如下:

撒花

^ <

✿✿✿✿✿✿✿✿✿✿✿✿✿✿✿

✿✿✿✿✿✿✿✿✿✿✿✿✿✿ ✿

✿✿✿✿✿✿✿✿✿✿✿✿✿✿✿

相关推荐
Pniubi8 小时前
HashMap的扩容和树化边界
java·开发语言
Mikko78 小时前
用 Java 复刻了高中时在塞班上玩的「熔岩矿车」:纯 Swing、零依赖、没有一张图片,一个 jar 双击就能玩
java·游戏开发·swing
知了学历孙老师8 小时前
小自考的校考和统考,出题方和难度差在哪
java·大数据·前端
Java爱好狂.8 小时前
Java初学者如何一周速通SpringBoot!
java·spring boot·后端·spring·高并发·架构师·java面试
秋饼9 小时前
LLM API密钥动态轮换实战:Spring Vault + Spring AI + 多Provider路由
java·ai·技术分享·后端开发
马良神笔10 小时前
2026 年Rag最近技术前沿总结
后端·python·django
程序猿DD10 小时前
同样10美元,OpenDesign和Command Code的DeepSeek V4.1 Flash额度到底有多少?
后端
福兮说11 小时前
JSON 格式正确,数据就可靠吗?我用一份自编配置检查类型与空值
java·前端·json
高频因子挖掘机11 小时前
A股量化从日线升级到5分钟线:数据量增加后最先暴露哪些工程问题?
后端·github·api
高频因子挖掘机11 小时前
历史行情返回顺序变了,为什么按行号计算指标很危险?
后端·github·api