Spring ApplicationContext(六)BeanPostProcessor

产生回顾一下 ApplicationContext 初始化的几个步骤:第一步是刷新环境变量;第二步是刷新 beanFactory 并加载 BeanDefinition;第三步是对 beanFactory 进行功能扩展,如增加 SPEL 支持和属性编辑器;第四步是留给子类实现的。

上一节中向 Spring 中注册将执行了 BeanFactoryPostProcessor,本节则继续探讨一下 BeanPostProcessor 的注册及调用时机。

public interface BeanPostProcessor {
// 在初始化之前调用
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
// 在初始化之后调用
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}
  1. BeanPostProcessor 什么时候注册?

    BeanFactory 和 ApplicationContext 容器的注册方式不大一样:若使用 BeanFactory,则必须要显示的调用其 addBeanPostProcessor() 方法进行注册;如果是使用 ApplicationContext,那么容器会在配置文件在中自动寻找实现了 BeanPostProcessor 接口的 Bean,然后自动注册。

  2. BeanPostProcessor 如何确保调用顺序?

    假如我们使用了多个的 BeanPostProcessor 的实现类,那么如何确定处理顺序呢?其实只要实现 Ordered 接口,设置 order 属性就可以很轻松的确定不同实现类的处理顺序了;

    接口中的两个方法都要将传入的 bean 返回,而不能返回 null,如果返回的是 null 那么我们通过 getBean() 方法将得不到目标。

一、BeanPostProcessor 的注册

源代码【AbstractApplicationContext】

@Override
public void refresh() throws BeansException, IllegalStateException {
// 6. 注册 BeanPostProcessor 后置处理器,在 getBean() 创建 bean 时调用
registerBeanPostProcessors(beanFactory); /**
* 1. 实例化剩余的所有非延迟加载单例对象
* 2. 为什么说是剩余的?因为在上面的 registerBeanPostProcessors 中已经把所有 BeanPostProcessors 所有对象都已经实例化过了;
* 3. 这加载的时候会判断 bean 是不是 FactoryBean 类型的
* 3.1 如果是 FactoryBean 类型,则 getBean(&beanName),这里是把 FactoryBean 本身的对象给实例化了,而没有调它的 getObject 方法;
* 3.2 如果不是 FactoryBean 类型,直接 getBean() 就行了;
* 4. 还要判断是不是 SmartInitializingSingleton 接口,这个接口有个 afterSingletonsInstantiated 方法;
*/
finishBeanFactoryInitialization(beanFactory);
} protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
}

源代码【PostProcessorRegistrationDelegate】

public static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
// 1. 此时 BeanDefinition 已经加载,只是 bean 还没有被实例化
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false); // 2. 记录日志用
// 可能已经注册了部分 BeanFactoryPostProcessors 接口
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount)); // 3. 按 PriorityOrdered internal Ordered nonOrdered 四个级别
// 3.1 优先级最高的 BeanPostProcessors,这类最先调用;需要实现 PriorityOrdered 接口
List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanPostProcessor>();
// 3.2 内部 BeanPostProcessors
List<BeanPostProcessor> internalPostProcessors = new ArrayList<BeanPostProcessor>();
// 3.3 继承了 Ordered 接口,优先级比上面低一点
List<String> orderedPostProcessorNames = new ArrayList<String>();
// 3.4 这就是普通的了,优先级最低
List<String> nonOrderedPostProcessorNames = new ArrayList<String>();
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
priorityOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
} // 4. PriorityOrdered internal Ordered nonOrdered 分别排序、初始化、注册
// 4.1 PriorityOrdered BeanPostProcessors
sortPostProcessors(beanFactory, priorityOrderedPostProcessors);
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors); // 4.2 Ordered BeanPostProcessors
List<BeanPostProcessor> orderedPostProcessors = new ArrayList<BeanPostProcessor>();
for (String ppName : orderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
orderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
sortPostProcessors(beanFactory, orderedPostProcessors);
registerBeanPostProcessors(beanFactory, orderedPostProcessors); // 4.3 nonOrdered BeanPostProcessors
List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<BeanPostProcessor>();
for (String ppName : nonOrderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
nonOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors); // 4.4 internal BeanPostProcessors
// 注意重复注册会先删除先注册的元素加添加到集合最后面,影响执行顺序
sortPostProcessors(beanFactory, internalPostProcessors);
registerBeanPostProcessors(beanFactory, internalPostProcessors); beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
} private static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanPostProcessor> postProcessors) { for (BeanPostProcessor postProcessor : postProcessors) {
beanFactory.addBeanPostProcessor(postProcessor);
}
}

源代码【AbstractBeanFactory】

private final List<BeanPostProcessor> beanPostProcessors = new ArrayList<BeanPostProcessor>();

@Override
public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
Assert.notNull(beanPostProcessor, "BeanPostProcessor must not be null");
// 如果已经注册则删除后重新注册,影响其执行顺序,如 internal 中的 MergedBeanDefinitionPostProcessor
this.beanPostProcessors.remove(beanPostProcessor);
this.beanPostProcessors.add(beanPostProcessor);
if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
this.hasInstantiationAwareBeanPostProcessors = true;
}
if (beanPostProcessor instanceof DestructionAwareBeanPostProcessor) {
this.hasDestructionAwareBeanPostProcessors = true;
}
}

总结:

(1) 最后 BeanPostProcessor 的注册顺序为 PriorityOrdered、Ordered、nonOrdered、internal,其中 internal 又分为 PriorityOrdered、Ordered、nonOrdered 三种顺序。

二、BeanPostProcessor 实战

class PriorityOrderTest implements BeanPostProcessor, PriorityOrdered {}
class OrderTest implements BeanPostProcessor, Ordered {}
class NoneTest implements BeanPostProcessor {}

三、BeanPostProcessor 调用时机

源代码【AbstractAutowireCapableBeanFactory】

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
//省略...
populateBean(beanName, mbd, instanceWrapper);
if (exposedObject != null) {
// BeanPostProcessors 两个方法都在这里面
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
} protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
// 省略 ...
invokeAwareMethods(beanName, bean); Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// 初始化前
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
} try {
// 初始化
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(ex);
} if (mbd == null || !mbd.isSynthetic()) {
// 初始化后
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
} @Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException { Object result = existingBean;
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
result = beanProcessor.postProcessBeforeInitialization(result, beanName);
if (result == null) {
return result;
}
}
return result;
}

每天用心记录一点点。内容也许不重要,但习惯很重要!

Spring ApplicationContext(五)invokeBeanFactoryPostProcessors的更多相关文章

  1. Spring ApplicationContext(一)初始化过程

    Spring 容器 ApplicationContext(一)初始化过程 Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html) ...

  2. Spring第五篇

    在Spring第四篇中 我们主要介绍了set get的注入方式 在Spring第五篇中 我们主要介绍使用注解配置Spring 主要分为两个步骤 1 导包的同时引入新得约束 导包如下 1.1 重写注解代 ...

  3. 以静态变量保存 Spring ApplicationContext

    package com.thinkgem.jeesite.common.utils; import java.net.HttpURLConnection; import java.net.URL; i ...

  4. Spring点滴五:Spring中的后置处理器BeanPostProcessor讲解

    BeanPostProcessor接口作用: 如果我们想在Spring容器中完成bean实例化.配置以及其他初始化方法前后要添加一些自己逻辑处理.我们需要定义一个或多个BeanPostProcesso ...

  5. Spring ApplicationContext(二)环境准备

    Spring ApplicationContext(二)环境准备 Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html) 本节介绍 ...

  6. Spring ApplicationContext(六)BeanPostProcessor

    Spring ApplicationContext(六)BeanPostProcessor 产生回顾一下 ApplicationContext 初始化的几个步骤:第一步是刷新环境变量:第二步是刷新 b ...

  7. Spring ApplicationContext(八)事件监听机制

    Spring ApplicationContext(八)事件监听机制 本节则重点关注的是 Spring 的事件监听机制,主要是第 8 步:多播器注册:第 10 步:事件注册. public void ...

  8. Caused by: java.io.FileNotFoundException: Could not open ServletContext resource [/config/spring/applicationContext.xml]

    在搭建SpringMVC框架的时候遇到了这个问题 问题的原因: 就是没有找到applicatoincontext.xml这个文件, 因为idea自动生成的路径不正确 因此需要再web.xml里面, ( ...

  9. 使用Arthas 获取Spring ApplicationContext还原问题现场

    ## 背景 最近来了个实习僧小弟,安排他实现对目标网站 连通性检测的小功能,简单讲就是将下边的shell 脚本换成Java 代码来实现 ``` 1#!/bin/bash 2URL="http ...

随机推荐

  1. 径向模糊(Radial Blur)

    [径向模糊(Radial Blur)] 径向模糊,是一种从中心向外呈幅射状的逐渐模糊的效果,在图形处理软件photoshop里面也有这个模糊滤镜.而在游戏中常常用来模拟一些动感的效果,如鬼泣4中的场景 ...

  2. 算法之LOWB三人组之冒泡排序

    排序 冒泡排序(Bubble Sort)时间复杂度为O(n^2) 列表每两个相邻的数,如果前面比后面大,则交换这两个数 一趟排序完成后,则无序区减少一个数,有序区增加一个数. def bubble_s ...

  3. jackson支持LocalDate等java8时间

    pom文件增加依赖: <dependency> <groupId>com.fasterxml.jackson.datatype</groupId> <arti ...

  4. 【scrapy】其他问题

    今天看<python爬虫开发与项目实践>的17章写代码的时候发现,一个方法的结尾带了红色波浪线: def _process_booklist_item(self,item): ''' 处理 ...

  5. IMPDP NETWORK_LINK参数

    在<[IMPDP]同一数据库实例不同用户间数据迁移复制—— NETWORK_LINK参数>(http://space.itpub.net/519536/viewspace-631571)文 ...

  6. openvpn-admin(openvpn web管理 )

    openvpn 两种认证简介: 1.key分发: 在服务器端生成秘钥,然后下载到本地,将服务器端的ca.crt xx.crt xx.key ta.key(如果服务器启用的话需要,未开启的话不需要,功能 ...

  7. 超详细 Nginx 极简教程

    什么是Nginx? Nginx (engine x) 是一款轻量级的Web 服务器 .反向代理服务器及电子邮件(IMAP/POP3)代理服务器. 什么是反向代理? 反向代理(Reverse Proxy ...

  8. 全国绿色计算大赛 模拟赛第一阶段(C++)第1关:求和

    挑战任务 这次“绿盟杯”大赛,小明作为参赛选手在练习的时候遇到一个问题,他要对一个范围的两个数进行数位的累加,例如有两个数 15,19 则 他们的数位和应该为:1+5+1+6+1+7+1+8+1+9, ...

  9. ucore-lab1-练习4report

    练习四:分析bootloader加载ELF格式的OS的过程  1.bootloader如何读取硬盘扇区? (1)在练习3中实现了bootloader让CPU进入保护模式,下一步的工作就是从硬盘上加载并 ...

  10. Markdown总结整理

    今天朋友(SolskGare)向我普及了一个很方便的文本编辑语言Markdown,才意识到之前自己用鼠标一点一点的排版有多low,而且往往还是费力不讨好.今天我就整理一下Markdown的用法,真的是 ...