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. Error:No toolchains found in the NDK toolchains folder for ABI with prefix: mips64el-linux-android

    https://www.jianshu.com/p/fd3d49c7f1f8 通过Android Studio 的Sdk Manager安装NDK,安装完之后编译失败,报错信息如下: Error:No ...

  2. spring boot 代理(not eligible for auto-proxying)

    spring 事务机制网上的案例很多,关于事务 不能回滚也有很多的类型,不同的问题有不同的处理方案,本篇博客主要介绍两种事务不能回滚的问题解决方案: 问题一:    在同一个对象中有两个方法,分别未方 ...

  3. IN_ORDER_PLANNING、IN_BOM_CHANGE

    一.IN_ORDER_PLANNING 新增一个IN表(IN_ORDER_PLANNING,把ZFP037和ZFP026整合成一张表,标示哪些订单的是真验货/假验货.VIP真验货/假验货订单) ORD ...

  4. sqlserver 查看当前连接数

    参考 https://www.cnblogs.com/lumnm/archive/2009/08/29/1556349.html SELECT * FROM[Master].[dbo].[SYSPRO ...

  5. H3C S5800 MPLS----VPLS 三层路由透传二层网络

    一.MPLS 介绍 多协议标签交换(Multi-Protocol Label Switching,MPLS)是新一代的IP高速骨干网络交换标准,由因特网工程任务组(Internet Engineeri ...

  6. 网页请求get方式

    方法都是博客中的大神写的,谢谢各路大神. 方法一:(亲测有效) //Get请求方式 private string RequestGet(string Url) { string PageStr = s ...

  7. Codeforces Round #518 (Div. 2) [Thanks, Mail.Ru!]

    Codeforces Round #518 (Div. 2) [Thanks, Mail.Ru!] https://codeforces.com/contest/1068 A #include< ...

  8. jquery一些容易混淆的

    1.父级元素.append子集元素 == 子集元素.appendTo父级元素 2.父级元素.prepend子集元素 == 子集元素.prependTo父级元素 3.同辈1.insertBefore同辈 ...

  9. 在IDEA中使用MyBatis Generator逆向工程生成代码

    本文介绍一下用Maven工具如何生成Mybatis的代码及映射的文件. 一.配置Maven pom.xml 文件 在pom.xml增加以下插件: <build> <finalName ...

  10. http406错误

    The resource identified by this request is only capable of generating responses with characteristics ...