Spring ApplicationContext(六)BeanPostProcessor
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;
}
- BeanPostProcessor 什么时候注册?
BeanFactory 和 ApplicationContext 容器的注册方式不大一样:若使用 BeanFactory,则必须要显示的调用其 addBeanPostProcessor() 方法进行注册;如果是使用 ApplicationContext,那么容器会在配置文件在中自动寻找实现了 BeanPostProcessor 接口的 Bean,然后自动注册。
- 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的更多相关文章
- Spring ApplicationContext(一)初始化过程
Spring 容器 ApplicationContext(一)初始化过程 Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html) ...
- Spring ApplicationContext(五)invokeBeanFactoryPostProcessors
Spring ApplicationContext(六)BeanPostProcessor 产生回顾一下 ApplicationContext 初始化的几个步骤:第一步是刷新环境变量:第二步是刷新 b ...
- Spring中的BeanPostProcessor详解
Spring中的BeanPostProcessor详解 概述 BeanPostProcessor也称为Bean后置处理器,它是Spring中定义的接口,在Spring容器的创建过程中(具体为Bean初 ...
- 以静态变量保存 Spring ApplicationContext
package com.thinkgem.jeesite.common.utils; import java.net.HttpURLConnection; import java.net.URL; i ...
- Spring Boot(六):如何使用mybatis
Spring Boot(六):如何使用mybatis orm框架的本质是简化编程中操作数据库的编码,发展到现在基本上就剩两家了,一个是宣称可以不用写一句SQL的hibernate,一个是可以灵活调试动 ...
- Spring ApplicationContext(二)环境准备
Spring ApplicationContext(二)环境准备 Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html) 本节介绍 ...
- Spring ApplicationContext(八)事件监听机制
Spring ApplicationContext(八)事件监听机制 本节则重点关注的是 Spring 的事件监听机制,主要是第 8 步:多播器注册:第 10 步:事件注册. public void ...
- Spring点滴六:Spring中定义bean的继承
在基于XML配置元数据中,bean标签可以包含很多配置信息,可以包含构造函数的参数,属性值以及其他一些初始化方法.子bean的定义可以继承父bean定义元数据,子bean定义可以根据需要重写父bean ...
- Caused by: java.io.FileNotFoundException: Could not open ServletContext resource [/config/spring/applicationContext.xml]
在搭建SpringMVC框架的时候遇到了这个问题 问题的原因: 就是没有找到applicatoincontext.xml这个文件, 因为idea自动生成的路径不正确 因此需要再web.xml里面, ( ...
随机推荐
- java第一课总结
转眼间开学了,我们也正式进入了大二.心里既有激动,又有些感慨,还带有一些担忧.激动的是我们褪去了大一的稚气成为了一名大二的学长了,第一次体会到了大学学长的感觉,心里很是激动.感慨的是我们又成长了一岁, ...
- 第二篇:Jmeter功能概要
一.jmeter工具组成部分: 1.资源生成器:用于生成测试过程中服务器,负载机的资源代码: 2.用户运行器:通常是一个脚本运行引擎,根据脚本的要求模拟指定用户行为,(lr中的controller) ...
- streaming窗口操作
之前一直对窗口操作不太理解.认为spark streaming本身已经是分片计算,还需要窗口操作干啥. 窗口操作最为简单易懂的场景就是,在M时间间隔计算一次N时间内的热搜.当M=N的时候,就像上述所说 ...
- 【scrapy】其他问题2
今天爬取豆瓣电影的是时候,出现了两个问题: 1.数据无法爬取并输出Retrying <GET https://movie.douban.com/robots.txt> 看起来像是被拦截了. ...
- pta7-18奥运排行榜(模拟)
题目链接:https://pintia.cn/problem-sets/1101307589335527424/problems/1101314114867245056 题意:给n个国家,以及每个国家 ...
- 静态方法调用内部类时候的new 问题
package tool; /** * 静态方法调用内部类时候的new 问题 */ public class aa { // 静态方法 // 静态方法new 有问题 public static voi ...
- 【转】chrome devtools protocol——Web 性能自动化
前言 在测试Web页面加载时间时,可能会是这样的: 打开chrome浏览器. 按F12打开开发者工具. 在浏览器上打开要测试的页面 查看开发者工具中Network面板的页面性能数据并记录 或者在开发者 ...
- TOJ 3973 Maze Again && TOJ 3128 简单版贪吃蛇
TOJ3973传送门:http://acm.tzc.edu.cn/acmhome/problemdetail.do?&method=showdetail&id=3973 时间限制(普通 ...
- Maximum GCD(fgets读入)
Maximum GCD https://vjudge.net/contest/288520#problem/V Given the N integers, you have to find the m ...
- 模板】AC自动机(简单版)
模板]AC自动机(简单版) https://www.luogu.org/problemnew/show/P3808 这是一道简单的AC自动机模板题. 用于检测正确性以及算法常数. 为了防止卡OJ,在保 ...