[源码系列:手写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 ...
随机推荐
- .NET Core + Kafka 开发指南
什么是Kafka Apache Kafka是一个分布式流处理平台,由LinkedIn开发并开源,后来成为Apache软件基金会的顶级项目.Kafka主要用于构建实时数据管道和流式应用程序. Kafka ...
- Appium_WebDriverAgent安装
一.WebDriverAgent安装到ios测试设备 a) 切换到appium 的appium-webdriveragent目录(/Applications/Appium.app/Contents ...
- React基础笔记1
官网:https://react.docschina.org/ 一.认知React 概述 React 起源于 Facebook(脸书) 的内部项目,它是一个用于构建用户界面的 javascript 库 ...
- Diary -「联合省选 2023」鸢尾
零 她们诞生于那样一段迷茫的时期,她们总是一个唱着虚幻的梦呓,一个哼着现实的词曲. 「平行的世界 / 另一个 / 我是怎样的」?如果那时的,虚幻的歌者没有妥协,现在的她会是怎样的人呢? 我 ...
- 基于Tablestore打造亿量级订单管理解决方案
一.方案背景 订单系统存在于各行各业,如电商订单.银行流水.运营商话费账单等,是一个非常广泛.通用的系统.对于这类系统,在过去十几年发展中已经形成了经典的做法.但是随着互联网的发展,以及各企业对数据的 ...
- 在线客服系统 QPS 突破 240/秒,连接数突破 4000,日请求数接近1000万次,.NET 多线程技术的高性能实践
背景 我在业余时间开发了一款自己的独立产品:升讯威在线客服与营销系统.陆陆续续开发了几年,从一开始的偶有用户尝试,到如今的 QPS 突破 240 次/秒,连接数突破 4000,日请求数接近 1000 ...
- 开源标杆!天翼云TeleDB入选《2024央国企开源项目典型实践》!
近日,由中国通信标准化协会主办.中国信通院承办的2024 OSCAR开源产业大会在北京召开,会上发布<2024央国企开源项目典型实践>,天翼云科技有限公司打造的"TeleDB分布 ...
- JDK8到JDK17都升级了那些新特性?又有哪些能常用好用的?
JDK8到JDK17都升级了那些新特性?又有哪些能常用好用的? 最近要做一个项目升级,因为之前的项目中有用到ElasticSearch 7.10.1版本,在之前的漏扫环节时会出现Tomcat渗透为问题 ...
- RabbitMQ(八)——消息确认
RabbitMQ系列 RabbitMQ(一)--简介 RabbitMQ(二)--模式类型 RabbitMQ(三)--简单模式 RabbitMQ(四)--工作队列模式 RabbitMQ(五)--发布订阅 ...
- 『Python底层原理』--CPython的变量实现机制
在Python中,变量的使用看起来非常简单,例如 a = 10,s = "hello"等等. 然而,这种简单的赋值操作背后,CPython其实做了很多复杂的工作. 本文将通过一些简 ...
https://github.com/yihuiaa/little-spring/tree/bean-factory-post-processor-and-bean-post-processor