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原理解析的切面实现过程(将切面类的所 ...
随机推荐
- 安卓中运行报错Error:Execution failed for task ':app:transformClassesWithDexForDebug'解决
在androidstuio中运行我的未完项目,报错: Error:Execution failed for task ':app:transformClassesWithDexForDebug'.&g ...
- Jmeter线程组使用详解,持续加压线程组详解
以下罗列的是Jmeter 所有线程组的详解,包括官方自带的线程组,和官方插件的线程组.官方线程组安装,详见之前的文章:https://www.cnblogs.com/beimingyouyuqingc ...
- 保存会话数据的两种技术,Cookie,Session
CookieCookie是客户端技术,服务器把每个用户的数据以cookie的形式写给用户各自的浏览器.当用户使用浏览器再去访问服务器中的web资源时,就会带着各自的数据去.这样,web资源处理的就是用 ...
- python入门之字符串的魔法
1.test="alex" v=test.capitalize() print(v) //输出结果首字母大写 2.test1="alex&qu ...
- css3新增属性有哪些?css3中常用的新增属性总结
css3新增属性有哪些?来提问这个问题的人都应该知道css3是css的升级版本,那么,css3既然是升级版本,自然是会新增一些属性,接下来本篇文章将给大家介绍关于css3中常用的新增属性. 一.css ...
- k8s集群---apiserver,controller-manager,scheduler部署
#证书自签名脚本 root@k8s-master: ~/k8s/k8s-cert :: $ cat k8s-cert.sh cat > ca-config.json <<EOF { ...
- Ubuntu 18.04 64位安装tensorflow-gpu
第一步(可直接跳到第二步):安装nvidia显卡驱动 linux用户可以通过官方ppa解决安装GPU驱动的问题.使用如下命令添加Graphic Drivers PPA: 1 sudo add-apt- ...
- springboot-实现文件下载
一 前言 本文实现的文件下载是使用Apache 的 commons-fileupload 实现:在之前的springboot系列文件中已经讲述过如何实现多文件上传:这篇文件实现的文件下载功能主要是能在 ...
- php hash比较缺陷
PHP在处理哈希字符串时,会利用”!=”或”==”来对哈希值进行比较,它把每一个以”0E”开头的哈希值都解释为0,所以如果两个不同的密码经过哈希以后,其哈希值都是以”0E”开头的,那么PHP将会认为他 ...
- 利用 Hexo 或者 hugo 搭建个人博客
我们无法选择生活的样子,但我们可以记下来. 博客的开始 其实,一切都是为了更好的装逼.好吧,我着相了. 最开始想做一个自己博客,主要是因为看到了很多人都有,觉得自己没有太 Low 了.于是申请了 CS ...