内容介绍

BeanFactoryPostProcessor和BeanPostProcessor是spring中具有重量级地位的两个接口,理解了这两个接口的主要作用,基本就理解Spring的核心原理了。为了便于理解将分成两篇文章介绍。

BeanFactoryPostProcessor

BeanFactoryPostProcessor是spring容器的后置处理器,是spring提供的容器扩展机制,它的调用时机是在spring容器实例化任何一个bean之前,也就是说在容器完成BeanDefinition读取之后,bean实例化之前。这个后置处理器可以操作容器中的bean定义信息,可以修改属性值,也可以添加新的bean定义信息。重要的实现类有以下两个:

  • PropertyPlaceholderConfigurer:用properties文件的配置值替换xml文件中的占位符
  • CustomEditorConfigurer:实现类型转换。

BeanFactoryPostProcessor的实现比较简单,大家可以根据下面的单元测试debug一下。

BeanPostProcessor

BeanPostProcessor也是spring提供的容器扩展机制,而它的调用时机是在每一个bean实例化之后,在初始化方法调用之前和之后。BeanPostProcessor可以对bean的属性进行更改,它也可以返回一个完全不同的实例来替换掉原来的bean,也是后面实现AOP的关键。

BeanPostProcessor的两个方法分别在bean执行初始化方法(后面实现)之前和之后执行。

public interface BeanPostProcessor {
/**
* 在bean执行初始化方法之前执行此方法
*/
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException; /**
* 在bean执行初始化方法之后执行此方法
*/
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}

代码仓库

完整代码

bean-factory-post-processor-and-bean-post-processorhttps://github.com/yihuiaa/little-spring/tree/bean-factory-post-processor-and-bean-post-processor


核心代码

BeanFactoryPostProcessor接口

定义bean处置方法,允许自定义修改BeanDefinition的属性值。

/**
* ● @author: YiHui
* ● @date: Created in 21:37 2023/4/17
* ● @notes: 允许自定义修改BeanDefinition的属性值
*/
public interface BeanFactoryPostProcessor {
/**
* BeanDefinition加载完成后,bean实例化之前,提供修改BeanDefinition属性值的机制
* @param beanFactory
* @throws BeansException
*/
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}

BeanPostProcessor接口

定义bean处置方法,用于修改实例化后的bean的修改扩展点。

/**
* ● @author: YiHui
* ● @date: Created in 22:21 2023/4/17
* ● @notes: 用于修改实例化后的bean的修改扩展点
*/
public interface BeanPostProcessor {
/**
* 在bean执行初始化方法之前执行此方法
*
* @param bean
* @param beanName
* @return
* @throws BeansException
*/
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException; /**
* 在bean执行初始化方法之后执行此方法
*
* @param bean
* @param beanName
* @return
* @throws BeansException
*/
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}

AutowireCapableBeanFactory

定义BeanFactory的自动装载方法

public interface AutowireCapableBeanFactory extends BeanFactory {
/**
* 执行BeanPostProcessors的postProcessBeforeInitialization方法
* @param existingBean
* @param beanName
* @return
* @throws BeansException
*/
Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException; /**
* 执行BeanPostProcessors的postProcessAfterInitialization方法
* @param existingBean
* @param beanName
* @return
* @throws BeansException
*/
Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException;
}

AbstractBeanFactory

添加beanPostProcessors列表属性

/**
* ● @author: YiHui
* ● @date: Created in 16:20 2023/2/20
* ● @notes:抽象bean工厂,提供获取bean的模版方法
*/
public abstract class AbstractBeanFactory extends DefaultSingletonBeanRegistry implements ConfigurableBeanFactory { private final List<BeanPostProcessor> beanPostProcessors = new ArrayList<>(); public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor){
//有则覆盖
beanPostProcessors.remove(beanPostProcessor);
beanPostProcessors.add(beanPostProcessor);
} public List<BeanPostProcessor> getBeanPostProcessors() {
return beanPostProcessors;
} 省略其他代码...

AbstractAutowireCapableBeanFactory

createBean方法修改,bean实例化时新增bean初始化方法的调用。

...

@Override
protected Object createBean(String name, BeanDefinition beanDefinition,Object[] args) {
Object bean = null;
try {
bean = createBeanInstance(name,beanDefinition,args);
//填充属性
applyPropertyValues(name,bean, beanDefinition);
//执行bean的初始化方法和BeanPostProcessor的前置和后置处理方法
initializeBean(name, bean, beanDefinition);
}catch(Exception e){
throw new BeansException("Fail to instantiation",e);
}
addSingleton(name,bean);
return bean;
} ...

新增bean初始化方法

...   

protected Object initializeBean(String beanName, Object bean,BeanDefinition beanDefinition){
//执行BeanPostProcessor的前置处理
Object wrappedBean = applyBeanPostProcessorsBeforeInitialization(bean, beanName);
// todo 执行bean初始化
invokeInitMethods(beanName,bean, beanDefinition);
//执行BeanPostProcessor的后置处理
wrappedBean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
return wrappedBean;
}
...

测试

spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <bean id="person" class="bean.Person">
<property name="name" value="yiHui"/>
<property name="car" ref="car"/>
</bean> <bean id="car" class="bean.Car">
<property name="name" value="Rolls-Royce"/>
</bean> </beans>

BeanFactoryPostProcessor

public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
BeanDefinition beanDefinition = beanFactory.getBeanDefinition("person");
PropertyValues propertyValues = beanDefinition.getPropertyValues();
//修改name
propertyValues.addPropertyValue(new PropertyValue("name","YiHuiComeOn"));
}
}
    @Test
public void BeanFactoryPostProcessor() throws Exception {
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(factory);
xmlBeanDefinitionReader.loadBeanDefinitions("classpath:spring.xml"); //BeanDefinition加载完成后,bean实例化之前,修改BeanDefinition的属性值
CustomBeanFactoryPostProcessor beanFactoryPostProcessor = new CustomBeanFactoryPostProcessor();
beanFactoryPostProcessor.postProcessBeanFactory(factory); Person person = (Person)factory.getBean("person");
System.out.println(person);
}

测试结果

名称在实例化之前由xml中定义的yiHui被改为YiHuiComeOn

执行bean[car]的初始化方法
执行bean[person]的初始化方法
Person{name='YiHuiComeOn', age='null', car=Car{name='Rolls-Royce'}}

BeanPostProcessor

public class CustomerBeanPostProcessor implements BeanPostProcessor {
@Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("CustomerBeanPostProcessor#postProcessBeforeInitialization");
//换玛莎
if("car".equals(beanName)){
((Car)bean).setName("Maserati");
}
return bean;
} @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("CustomerBeanPostProcessor#postProcessAfterInitialization");
return bean;
}
}
    @Test
public void testBeanPostProcessor() throws Exception {
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(factory);
xmlBeanDefinitionReader.loadBeanDefinitions("classpath:spring.xml"); //添加bean实例化后的处理器
factory.addBeanPostProcessor(new CustomerBeanPostProcessor()); Car car = (Car)factory.getBean("car");
System.out.println(car); }

测试结果

CustomerBeanPostProcessor#postProcessBeforeInitialization
执行bean[car]的初始化方法
CustomerBeanPostProcessor#postProcessAfterInitialization
Car{name='Maserati'}

[源码系列:手写spring] IOC第八节:BeanFactoryPostProcessor和BeanPostProcessor的更多相关文章

  1. Spring源码分析 手写简单IOC容器

    Spring的两大特性就是IOC和AOP. IOC Container,控制反转容器,通过读取配置文件或注解,将对象封装成Bean存入IOC容器待用,程序需要时再从容器中取,实现控制权由程序员向程序的 ...

  2. 《四 spring源码》手写springioc框架

    手写SpringIOCXML版本 /** * 手写Spring专题 XML方式注入bean * * * */ public class ClassPathXmlApplicationContext { ...

  3. 框架源码系列十:Spring AOP(AOP的核心概念回顾、Spring中AOP的用法、Spring AOP 源码学习)

    一.AOP的核心概念回顾 https://docs.spring.io/spring/docs/5.1.3.RELEASE/spring-framework-reference/core.html#a ...

  4. 从零开始手写 spring ioc 框架,深入学习 spring 源码

    IoC Ioc 是一款 spring ioc 核心功能简化实现版本,便于学习和理解原理. 创作目的 使用 spring 很长时间,对于 spring 使用非常频繁,实际上对于源码一直没有静下心来学习过 ...

  5. 框架源码系列六:Spring源码学习之Spring IOC源码学习

    Spring 源码学习过程: 一.搞明白IOC能做什么,是怎么做的  1. 搞明白IOC能做什么? IOC是用为用户创建.管理实例对象的.用户需要实例对象时只需要向IOC容器获取就行了,不用自己去创建 ...

  6. 《四 spring源码》手写springmvc

    手写SpringMVC思路 1.web.xml加载  为了读取web.xml中的配置,我们用到ServletConfig这个类,它代表当前Servlet在web.xml中的配置信息.通过web.xml ...

  7. Spring源码 20 手写模拟源码

    参考源 https://www.bilibili.com/video/BV1tR4y1F75R?spm_id_from=333.337.search-card.all.click https://ww ...

  8. 利用递归,反射,注解等,手写Spring Ioc和Di 底层(分分钟喷倒面试官)了解一下

    再我们现在项目中Spring框架是目前各大公司必不可少的技术,而大家都知道去怎么使用Spring ,但是有很多人都不知道SpringIoc底层是如何工作的,而一个开发人员知道他的源码,底层工作原理,对 ...

  9. Spring源码剖析3:Spring IOC容器的加载过程

    本文转自五月的仓颉 https://www.cnblogs.com/xrq730 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https ...

  10. 源码分析 | 手写mybait-spring核心功能(干货好文一次学会工厂bean、类代理、bean注册的使用)

    作者:小傅哥 博客:https://bugstack.cn - 汇总系列原创专题文章 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言介绍 一个知识点的学习过程基本分为:运行helloworld ...

随机推荐

  1. w3cschool-Linux 命令大全

    Linux关机命令和重启命令说明 在Linux中,常用的关机命令shutdown.halt.poweroff.init:重启命令有:reboot.本文将主要为大家带来一些常用的关机命令以及各种关机命令 ...

  2. Zookeeper的原理和架构设计,以及应用场景

    什么是 Zookeeper Zookeeper 分布式服务框架是Apache Hadoop 的一个子项目,它主要是用来解决分布式应用中经常遇到的一些数据管理问题,如: 统一命名服务 状态同步服务 集群 ...

  3. 揭秘10种主流PLC在ModbusTCP通信中的速度表现!

    大家好!我是付工. 通透!终于把ModbusRTU弄明白了 这样看来,ModbusTCP协议太简单了 太简单了!C#轻松实现Modbus通信 前面给大家介绍了一系列关于Modbus和ModbusTCP ...

  4. 找不到 MSVCP60D.dll

    问题 VC++ 运行程序时,出现错误: 解决办法 参考:链接 1.下载MSVCP60D.dll,下载:链接 下载的文件为64位,故应将文件复制到:C:\Windows\SysWOW64目录 2.打开& ...

  5. 字符流:FileReader/FileWriter的使用

    读取文件 1.建立一个流对象,将已存在的一个文件加载进流. FileReader fr = new FileReader(new File("Test.txt"));2.创建一个 ...

  6. 开发者新选择:用DeepSeek实现Cursor级智能编程的免费方案

    前言 去年下半年 cursor 非常火,让很多一行代码都不懂的小白,也可以做自己的网站和搭 App,当时一下子就引爆了独立开发的热潮. 不过每月20dollar的价格也不算便宜,这时候可以使用 cli ...

  7. Windows下安装和配置NodeJS

    1.下载 中文地址:https://nodejs.cn/download/ 官网地址:https://nodejs.org/en/download/ 如这里我们下载当前最新版:https://node ...

  8. 多节点oceanbase 集群部署

    安装前准备 硬件要求 CPU最少2核 磁盘最少19G 文件系统EXT4 戓 XFS 关闭透明大页 echo never > /sys/kernel/mm/redhat_transparent_h ...

  9. 深入集成:使用 DeepSeek SDK for .NET 实现自然语言处理功能

    快速上手:DeepSeek SDK for .NET 全面指南 简介 Ater.DeepSeek.AspNetCore 是专门为 .NET 开发者提供的 DeepSeek API SDK.它旨在简化与 ...

  10. ABB机器人IRB1600齿轮箱维修故障四大原因

    一.ABB机器人IRB1600齿轮箱齿轮磨损 齿轮磨损是IRB1600齿轮箱常见的故障.长时间的高速运转和负载作用会导致齿轮表面磨损,进而产生噪音和振动.维修时,需要对磨损的齿轮进行更换,同时检查相邻 ...