Spring中的BeanPostProcessor详解
Spring中的BeanPostProcessor详解
概述
- BeanPostProcessor也称为Bean后置处理器,它是Spring中定义的接口,在Spring容器的创建过程中(具体为Bean初始化前后)会回调BeanPostProcessor中定义的两个方法。BeanPostProcessor的源码如下
public interface BeanPostProcessor {
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}
- 其中postProcessBeforeInitialization方法会在每一个bean对象的初始化方法调用之前回调;postProcessAfterInitialization方法会在每个bean对象的初始化方法调用之后被回调。
执行原理
- BeanPostProcessor的执行是定义在容器的刷新过程中,容器刷新对象具体的方法为:AbstractApplicationContext.refresh()。在refresh方法执行的调用栈中会去调用AbstractAutowireCapableBeanFactory.doCreateBean()方法,该方法节选源码如下
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
invokeInitMethods(beanName, wrappedBean, mbd);
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
- 看到在调用初始化方法前后会分别调用applyBeanPostProcessorsBeforeInitialization()和applyBeanPostProcessorsAfterInitialization()。applyBeanPostProcessorsBeforeInitialization()方法的源码如下
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
//获取所有的BeanPostProcessor进行遍历
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
result = beanProcessor.postProcessBeforeInitialization(result, beanName);
if (result == null) {
return result;
}
}
return result;
}
- 可以看到其逻辑为遍历得到容器中所有的BeanPostProcessor,然后一次执行postProcessBeforeInitialization,一但返回null,就跳出for循环不执行后面的BeanPostProcessor.postProcessorsBeforeInitialization()。也就是说如果返回的是null那么我们通过getBean方法将得不到目标Bean。
- applyBeanPostProcessorsBeforeInitialization()方法的逻辑和上面一致,就是将循环执行的beanProcessor.postProcessBeforeInitialization()替换成beanProcessor.postProcessAfterInitialization()Spring底层的很多功能特性都是借助BeanPostProcessor的子类来实现。
常见BeanPostProcessor分析
下图是debug过程中,ApplicationContext对象中的包含的BeanPostProcessor。具体包含哪些BeanPostProcessor和具体应用程序相关,除了下标3中的MyBeanPostProcessor为自定义的BeanPostProcessor,其余均为Spring自带的BeanPostProcessor。

ApplicationContextAwareProcessor
- ApplicationContextAwareProcessor后置处理器的作用是,当应用程序定义的Bean实现ApplicationContextAware接口时注入ApplicationContext对象。
@Component
public class Car implements ApplicationContextAware { private ApplicationContext applicationContext; public Car(){
System.out.println("car instance...");
} @Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("ApplicationContextAware...setApplicationContext()");
this.applicationContext = applicationContext;
}
}
- 那Car是如何通过实现ApplicationContextAware接口就能获得ApplicationContext对象呢?答案是通过ApplicationContextAwareProcessor后置处理器来实现,我们来看看ApplicationContextAwareProcessor的源码
class ApplicationContextAwareProcessor implements BeanPostProcessor { private final ConfigurableApplicationContext applicationContext; private final StringValueResolver embeddedValueResolver; /**
* Create a new ApplicationContextAwareProcessor for the given context.
*/
public ApplicationContextAwareProcessor(ConfigurableApplicationContext applicationContext) {
this.applicationContext = applicationContext;
this.embeddedValueResolver = new EmbeddedValueResolver(applicationContext.getBeanFactory());
} @Override
public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
AccessControlContext acc = null;
// 这里bean是Car,它实现了ApplicationContextAware接口
if (System.getSecurityManager() != null &&
(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
invokeAwareInterfaces(bean);
} return bean;
} private void invokeAwareInterfaces(Object bean) {
if (bean instanceof Aware) {
if (bean instanceof EnvironmentAware) {
((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
}
if (bean instanceof EmbeddedValueResolverAware) {
((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
}
if (bean instanceof ResourceLoaderAware) {
((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
}
if (bean instanceof ApplicationEventPublisherAware) {
((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
}
if (bean instanceof MessageSourceAware) {
((MessageSourceAware) bean).setMessageSource(this.applicationContext);
}
if (bean instanceof ApplicationContextAware) {
// 会执行这里回调car重写的setApplicationContext方法,然后将this.applicationContext注入给Car
((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
}
}
} @Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
return bean;
} }
InitDestroyAnnotationBeanPostProcessor
- InitDestroyAnnotationBeanPostProcessor后置处理器是用来处理自定义的初始化方法和销毁方法。
- Spring中提供了3种自定义初始化和销毁方法:1.通过@Bean指定init-method和destroy-method属性;2.Bean实现InitializingBean(定义初始化逻辑),DisposableBean(定义销毁逻辑); 3.@PostConstruct:在bean创建完成并且属性赋值完成;来执行初始化方法@PreDestroy:在容器销毁bean之前通知我们进行清理工作
- InitDestroyAnnotationBeanPostProcessor的作用就是让第3种方式生效。先看看如何使用@PostConstruct和@PreDestroy注解。
@Component
public class Car { public Car(){
System.out.println("car instance...");
} /**
* 自定义的初始化方法
*/
@PostConstruct
public void init(){
System.out.println("car ... init...");
} /**
* 自定义的销毁方法
*/
@PreDestroy
public void detory(){
System.out.println("car ... detory...");
}
}
- InitDestroyAnnotationBeanPostProcessor会在Bean创建的时候通过反射的方式查找包含@PostConstruct和@PreDestroy注解的方法,然后再通过反射执行方法。我们来看看InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization()的源码
使用
- 我们定义一个类实现了BeanPostProcessor,默认是会对整个Spring容器中所有的bean进行处理。
public class ConfigValueBeanProcessor implements BeanPostProcessor ,Ordered {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
ReflectionUtils.doWithLocalFields(bean.getClass(), (field -> {
System.out.println(field.toString());
Value valueAnnotation = field.getAnnotation(Value.class);
if (valueAnnotation != null) {
if (Modifier.isStatic(field.getModifiers())) {
return;
}
}
}));
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
//配置类中定义bean
@Bean
public ConfigValueBeanProcessor getConfigValueBeanProcessor() {
return new ConfigValueBeanProcessor();
}
Spring中的BeanPostProcessor详解的更多相关文章
- spring中的scope详解
spring容器中的bean默认是单例模式的,改成非单例模式需要在类上加上@Scope("prototype") 1. scope概论 spring中scope是一个非常关键的概念 ...
- Spring中@Async用法详解及简单实例
Spring中@Async用法 引言: 在Java应用中,绝大多数情况下都是通过同步的方式来实现交互处理的:但是在处理与第三方系统交互的时候,容易造成响应迟缓的情况,之前大部分都是使用多线程来完成此类 ...
- Spring中applicationContext.xml详解
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.sp ...
- spring在IoC容器中装配Bean详解
1.Spring配置概述 1.1.概述 Spring容器从xml配置.java注解.spring注解中读取bean配置信息,形成bean定义注册表: 根据bean定义注册表实例化bean: 将bean ...
- Spring Boot中@ConditionalOnProperty使用详解
在Spring Boot的自动配置中经常看到@ConditionalOnProperty注解的使用,本篇文章带大家来了解一下该注解的功能. Spring Boot中的使用 在Spring Boot的源 ...
- Spring IoC @Autowired 注解详解
前言 本系列全部基于 Spring 5.2.2.BUILD-SNAPSHOT 版本.因为 Spring 整个体系太过于庞大,所以只会进行关键部分的源码解析. 我们平时使用 Spring 时,想要 依赖 ...
- Spring IoC 公共注解详解
前言 本系列全部基于 Spring 5.2.2.BUILD-SNAPSHOT 版本.因为 Spring 整个体系太过于庞大,所以只会进行关键部分的源码解析. 什么是公共注解?公共注解就是常见的Java ...
- Spring框架系列(8) - Spring IOC实现原理详解之Bean实例化(生命周期,循环依赖等)
上文,我们看了IOC设计要点和设计结构:以及Spring如何实现将资源配置(以xml配置为例)通过加载,解析,生成BeanDefination并注册到IoC容器中的:容器中存放的是Bean的定义即Be ...
- Spring框架系列(9) - Spring AOP实现原理详解之AOP切面的实现
前文,我们分析了Spring IOC的初始化过程和Bean的生命周期等,而Spring AOP也是基于IOC的Bean加载来实现的.本文主要介绍Spring AOP原理解析的切面实现过程(将切面类的所 ...
随机推荐
- Python14_中TK模块使用总结
事件的绑定: https://www.cnblogs.com/jerryspace/p/9836142.html https://www.cnblogs.com/progor/p/8505599.ht ...
- 使用windows api函数捕获SAP session的左下角消息句柄
背景:SAP session的左下角消息非常有用,我们在做SAP的自动化脚本时可以设法读到这个消息的内容,作为程序后续动作的判断条件.如下图: 比如小爬之前给财务的同事制作了一个批量导出 ...
- 配置一个yum私有仓库
使用一台服务器配置私有仓库做yum源,本身使用file,客户端使用http连接 安装http服务: [root@ceph1 ~]# yum -y install httpd 修改配置文件 Docume ...
- js对当前时间进行处理
//1.JS获取两个日期之间相差的天数 function getDaysBetween(dateString1, dateString2) { var startDate = Date.parse(d ...
- C# 初识接口 Interface
什么是接口? 接口(interface)用来定义一种程序的协定.实现接口的类或者结构要与接口的定义严格一致.有了这个协定,就可以抛开编程语言的限制(理论上).C#接口可以从多个基接口继承,而类或结构可 ...
- SpringBoot简介与快速入门
一.SpringBoot简介 1.1 原有Spring优缺点分析 1.1.1 Spring的优点分析 Spring是Java企业版(Java Enterprise Edition,JEE,也称J2EE ...
- java实现单向循环链表
链表图解 带头结点的链表: 不带头结点的链表: 区别 带头结点的链表容易代码实现 不带头结点的容易实现循环链表和双向链表 代码的实现 (增减 删除) 节点实现: public class node { ...
- 洛谷P2657 [SCOI2009]windy数 题解 数位DP
题目链接:https://www.luogu.com.cn/problem/P2657 题目大意:找区间 \([A,B]\) 范围内 不含前导零 且 相邻两个数字之差至少为2 的正整数的个数. 题目分 ...
- 1047 编程团体赛 (20 分)C语言
编程团体赛的规则为:每个参赛队由若干队员组成:所有队员独立比赛:参赛队的成绩为所有队员的成绩和:成绩最高的队获胜. 现给定所有队员的比赛成绩,请你编写程序找出冠军队. 输入格式: 输入第一行给出一个正 ...
- C语言之while循环
while循环能做什么??? 先来个概念格式,while循环的一般形式为: while(表达式){ 语句块 } 意思是,先计算"表达式"的值,当值为真(非0)时, 执行" ...