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,然后自动注册。

  1. 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(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", 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(六)BeanPostProcessor的更多相关文章

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

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

  2. Spring ApplicationContext(五)invokeBeanFactoryPostProcessors

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

  3. Spring中的BeanPostProcessor详解

    Spring中的BeanPostProcessor详解 概述 BeanPostProcessor也称为Bean后置处理器,它是Spring中定义的接口,在Spring容器的创建过程中(具体为Bean初 ...

  4. 以静态变量保存 Spring ApplicationContext

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

  5. Spring Boot(六):如何使用mybatis

    Spring Boot(六):如何使用mybatis orm框架的本质是简化编程中操作数据库的编码,发展到现在基本上就剩两家了,一个是宣称可以不用写一句SQL的hibernate,一个是可以灵活调试动 ...

  6. Spring ApplicationContext(二)环境准备

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

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

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

  8. Spring点滴六:Spring中定义bean的继承

    在基于XML配置元数据中,bean标签可以包含很多配置信息,可以包含构造函数的参数,属性值以及其他一些初始化方法.子bean的定义可以继承父bean定义元数据,子bean定义可以根据需要重写父bean ...

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

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

随机推荐

  1. java第一课总结

    转眼间开学了,我们也正式进入了大二.心里既有激动,又有些感慨,还带有一些担忧.激动的是我们褪去了大一的稚气成为了一名大二的学长了,第一次体会到了大学学长的感觉,心里很是激动.感慨的是我们又成长了一岁, ...

  2. 第二篇:Jmeter功能概要

    一.jmeter工具组成部分: 1.资源生成器:用于生成测试过程中服务器,负载机的资源代码: 2.用户运行器:通常是一个脚本运行引擎,根据脚本的要求模拟指定用户行为,(lr中的controller) ...

  3. streaming窗口操作

    之前一直对窗口操作不太理解.认为spark streaming本身已经是分片计算,还需要窗口操作干啥. 窗口操作最为简单易懂的场景就是,在M时间间隔计算一次N时间内的热搜.当M=N的时候,就像上述所说 ...

  4. 【scrapy】其他问题2

    今天爬取豆瓣电影的是时候,出现了两个问题: 1.数据无法爬取并输出Retrying <GET https://movie.douban.com/robots.txt> 看起来像是被拦截了. ...

  5. pta7-18奥运排行榜(模拟)

    题目链接:https://pintia.cn/problem-sets/1101307589335527424/problems/1101314114867245056 题意:给n个国家,以及每个国家 ...

  6. 静态方法调用内部类时候的new 问题

    package tool; /** * 静态方法调用内部类时候的new 问题 */ public class aa { // 静态方法 // 静态方法new 有问题 public static voi ...

  7. 【转】chrome devtools protocol——Web 性能自动化

    前言 在测试Web页面加载时间时,可能会是这样的: 打开chrome浏览器. 按F12打开开发者工具. 在浏览器上打开要测试的页面 查看开发者工具中Network面板的页面性能数据并记录 或者在开发者 ...

  8. TOJ 3973 Maze Again && TOJ 3128 简单版贪吃蛇

    TOJ3973传送门:http://acm.tzc.edu.cn/acmhome/problemdetail.do?&method=showdetail&id=3973 时间限制(普通 ...

  9. Maximum GCD(fgets读入)

    Maximum GCD https://vjudge.net/contest/288520#problem/V Given the N integers, you have to find the m ...

  10. 模板】AC自动机(简单版)

    模板]AC自动机(简单版) https://www.luogu.org/problemnew/show/P3808 这是一道简单的AC自动机模板题. 用于检测正确性以及算法常数. 为了防止卡OJ,在保 ...