[源码系列:手写spring] IOC第八节:BeanFactoryPostProcessor和BeanPostProcessor
内容介绍
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;
}
代码仓库
完整代码
核心代码
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的更多相关文章
- Spring源码分析 手写简单IOC容器
Spring的两大特性就是IOC和AOP. IOC Container,控制反转容器,通过读取配置文件或注解,将对象封装成Bean存入IOC容器待用,程序需要时再从容器中取,实现控制权由程序员向程序的 ...
- 《四 spring源码》手写springioc框架
手写SpringIOCXML版本 /** * 手写Spring专题 XML方式注入bean * * * */ public class ClassPathXmlApplicationContext { ...
- 框架源码系列十:Spring AOP(AOP的核心概念回顾、Spring中AOP的用法、Spring AOP 源码学习)
一.AOP的核心概念回顾 https://docs.spring.io/spring/docs/5.1.3.RELEASE/spring-framework-reference/core.html#a ...
- 从零开始手写 spring ioc 框架,深入学习 spring 源码
IoC Ioc 是一款 spring ioc 核心功能简化实现版本,便于学习和理解原理. 创作目的 使用 spring 很长时间,对于 spring 使用非常频繁,实际上对于源码一直没有静下心来学习过 ...
- 框架源码系列六:Spring源码学习之Spring IOC源码学习
Spring 源码学习过程: 一.搞明白IOC能做什么,是怎么做的 1. 搞明白IOC能做什么? IOC是用为用户创建.管理实例对象的.用户需要实例对象时只需要向IOC容器获取就行了,不用自己去创建 ...
- 《四 spring源码》手写springmvc
手写SpringMVC思路 1.web.xml加载 为了读取web.xml中的配置,我们用到ServletConfig这个类,它代表当前Servlet在web.xml中的配置信息.通过web.xml ...
- Spring源码 20 手写模拟源码
参考源 https://www.bilibili.com/video/BV1tR4y1F75R?spm_id_from=333.337.search-card.all.click https://ww ...
- 利用递归,反射,注解等,手写Spring Ioc和Di 底层(分分钟喷倒面试官)了解一下
再我们现在项目中Spring框架是目前各大公司必不可少的技术,而大家都知道去怎么使用Spring ,但是有很多人都不知道SpringIoc底层是如何工作的,而一个开发人员知道他的源码,底层工作原理,对 ...
- Spring源码剖析3:Spring IOC容器的加载过程
本文转自五月的仓颉 https://www.cnblogs.com/xrq730 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https ...
- 源码分析 | 手写mybait-spring核心功能(干货好文一次学会工厂bean、类代理、bean注册的使用)
作者:小傅哥 博客:https://bugstack.cn - 汇总系列原创专题文章 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言介绍 一个知识点的学习过程基本分为:运行helloworld ...
随机推荐
- linux网桥(Linux Bridge)的一些个人记录
目录 1. Linux Bridge简述 2. 网桥创建 创建 配置持久化 在Debian/Ubuntu系统上: 在CentOS/RHEL系统上: 启用和验证 3. 关于linux网桥不转发ip帧的问 ...
- CDS标准视图:维护包数据 I_MaintenancePackageData
视图名称:维护包数据 I_MaintenancePackageData 视图类型:基础 视图代码: 点击查看代码 @AbapCatalog.sqlViewName: 'IMAINTPCKGDATA' ...
- GD32F103C8T6看门狗
GD32F10x看门狗 两个看门狗设备(独立看门狗IWDG和窗口看门狗WWDG)可用来检测和解决由软件错误引起的故障: 当计数器达到给定的超时值时,触发一个中断(仅适用于窗口型看门狗)或产生系统复位. ...
- 魔乐开发者社区正式上线,AI开发者快来撩!
近日,由天翼云与华为联合打造的魔乐(Modelers)开发者社区,在天翼云中国行·贵州站活动现场上线发布.依托全场景开源模型资源.易用的模型开发套件,以及强大的共建共享生态系统等优势,社区将使能开发者 ...
- JavaScript数组(包括上一笔记都是ECMAScript对象),BOM对象,DOM对象,html DOM Enent(事件)
JavaScript数组(包括上一笔记都是ECMAScript对象),BOM对象,DOM对象,html DOM Enent(事件) 1.Arrary; var ret = new Arrary(1,2 ...
- 阿里的DataV和QuickBi区别
首先说下DataV吧 分为老版和新版(二者之间没有什么太大的差别,存在的基本都是组件上的配置或是更多不同组件的新增,但是如果你是在项目上进行开发,你首先要知道客户用的DataV用的是什么版本,如果你们 ...
- oracle 删除过期归档脚本
一.定时任务 crontab -e 编辑 每周6凌晨3点执行脚本 0 3 * * 6 . /home/oracle/scripts/arch_delete_before_60days_arch.sh ...
- linux安装Phoenix
1.下载对应hbase的版本 http://www.apache.org/dyn/closer.lua/phoenix/ 解压后找到phoenix-4.14.2-HBase-1.4-server.ja ...
- 流程控制之if选择结构
if单选择结构 if (布尔表达式){ //如果布尔表达式为ture将执行的语句 } 实例: package com.yeyue.struct; import java.util.Sc ...
- 《Indie Tools • 半月刊》第001期
引言:独立开发者工具分享 <INDIE TOOLS>专注于分享独立开发出海精选.最新.最实用的工具. 欢迎订阅半月刊:<INDIE TOOLS • 半月刊> 如果本文能给你提供 ...
https://github.com/yihuiaa/little-spring/tree/bean-factory-post-processor-and-bean-post-processor