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详解的更多相关文章

  1. spring中的scope详解

    spring容器中的bean默认是单例模式的,改成非单例模式需要在类上加上@Scope("prototype") 1. scope概论 spring中scope是一个非常关键的概念 ...

  2. Spring中@Async用法详解及简单实例

    Spring中@Async用法 引言: 在Java应用中,绝大多数情况下都是通过同步的方式来实现交互处理的:但是在处理与第三方系统交互的时候,容易造成响应迟缓的情况,之前大部分都是使用多线程来完成此类 ...

  3. Spring中applicationContext.xml详解

    <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.sp ...

  4. spring在IoC容器中装配Bean详解

    1.Spring配置概述 1.1.概述 Spring容器从xml配置.java注解.spring注解中读取bean配置信息,形成bean定义注册表: 根据bean定义注册表实例化bean: 将bean ...

  5. Spring Boot中@ConditionalOnProperty使用详解

    在Spring Boot的自动配置中经常看到@ConditionalOnProperty注解的使用,本篇文章带大家来了解一下该注解的功能. Spring Boot中的使用 在Spring Boot的源 ...

  6. Spring IoC @Autowired 注解详解

    前言 本系列全部基于 Spring 5.2.2.BUILD-SNAPSHOT 版本.因为 Spring 整个体系太过于庞大,所以只会进行关键部分的源码解析. 我们平时使用 Spring 时,想要 依赖 ...

  7. Spring IoC 公共注解详解

    前言 本系列全部基于 Spring 5.2.2.BUILD-SNAPSHOT 版本.因为 Spring 整个体系太过于庞大,所以只会进行关键部分的源码解析. 什么是公共注解?公共注解就是常见的Java ...

  8. Spring框架系列(8) - Spring IOC实现原理详解之Bean实例化(生命周期,循环依赖等)

    上文,我们看了IOC设计要点和设计结构:以及Spring如何实现将资源配置(以xml配置为例)通过加载,解析,生成BeanDefination并注册到IoC容器中的:容器中存放的是Bean的定义即Be ...

  9. Spring框架系列(9) - Spring AOP实现原理详解之AOP切面的实现

    前文,我们分析了Spring IOC的初始化过程和Bean的生命周期等,而Spring AOP也是基于IOC的Bean加载来实现的.本文主要介绍Spring AOP原理解析的切面实现过程(将切面类的所 ...

随机推荐

  1. Sybase commands

    (1)update table statistics $table name if we change index info for a table ,such as create or drop i ...

  2. HRegion 分配与寻址

    1.Region 分配   HMaster负责为Region 分配Region Server,一个Region 只能分配给一个Region server. HMaster中 记录:   哪些Regio ...

  3. 洛谷$P5444\ [APIO2019]$奇怪装置 数论

    正解:数论 解题报告: 传送门$QwQ$ 我好像当初考的时候这题爆零了,,,部分分都没想到,,,我真的好菜$kk$ 考虑如果在$t_1,t_2$两个时刻有$x_1=x_2,y_1=y_2$是什么情况$ ...

  4. 浅谈Java的默认和静态方法

    目录 浅谈Java的默认和静态方法 Java新增默认方法有啥用 Java新增的静态方法有啥用 浅谈Java的默认和静态方法 允许在接口中声明默认方法和静态方法,是JDK1.8新增的特性.存在即合理,两 ...

  5. ES6异步操作之Promise

    一直以来觉得异步操作在我心头像一团迷雾,可是它重要到我们非学不可,那就把它的面纱解开吧. ES6 诞生以前,异步编程的方法,大概有下面四种. 回调函数 事件监听 发布/订阅 Promise 对象 异步 ...

  6. 「2018-11-05模拟赛」T5 传送机 解题报告

    5.传送机(sent.*) 问题描述: 黄黄同学要到清华大学上学去了.黄黄同学很喜欢清华大学的校园,每次去上课时总喜欢把校园里面的每条路都走一遍,当然,黄黄同学想每条路也只走一遍. 我们一般人很可能对 ...

  7. 「洛谷P1343」地震逃生 解题报告

    P1343 地震逃生 题目描述 汶川地震发生时,四川XX中学正在上课,一看地震发生,老师们立刻带领x名学生逃跑,整个学校可以抽象地看成一个有向图,图中有n个点,m条边.1号点为教室,n号点为安全地带, ...

  8. Vue.js项目在apache服务器部署后,刷新404的问题

    原因是vue-router 使用了路由的 history 模式,这种模式充分利用 history.pushState API 来完成 URL 跳转而无须重新加载页面. const router = n ...

  9. config.xml写入和读取

    using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threa ...

  10. ECOS问题解决记录

    1.finder自定义列 http://club.ec-os.net/doc/ecos/framework-ecos/advance/desktop/dev.html#id5 2.命令行工具 地址 h ...