Spring注解驱动之BeanFactoryPostProcessor原理解析

 更新时间:2022年09月30日 09:41:19   作者:融极  
这篇文章主要介绍了Spring注解驱动之BeanFactoryPostProcessor原理,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

概述

我们现在来学习一下Spring里面的一些扩展原理,希望大家通过这些原理的学习,对Spring里面的运行机制,包括其内部的工作原理,能有一个非常深刻的认识,为以后学习Spring里面的其他框架会有较大的帮助。

BeanFactoryPostProcessor的调用时机

BeanFactoryPostProcessor其实就是BeanFactory(创建bean的工厂)的后置处理器。

看到BeanFactoryPostProcessor会联想到BeanPostProcessor,之前说过它是bean的后置处理器,并且是在bean创建对象初始化前后进行拦截工作的。

看完接口上的描述后,我们可以指定BeanFactoryPostProcessor的调用时机。意思是在IOC容器的BeanFactory标准初始化完成之后,修改IOC容器里面的BeanFactory。

什么是标准初始化么?后面描述是所有的bean定义已经被加载了,但是还没有bean被初始化。

总结:BeanFactoryPostProcessor的调用时机是在BeanFactory标准化之后,我们可以定制、修改BeanFactory里面的一些内容,此时,所有的bean定义已经被加载到BeanFactory中了,但是bean的实例还没创建。

案例实践

首先编写一个类实现BeanFactoryPostProcessor接口。

package com.meimeixia.ext;
import java.util.Arrays;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;

@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
		System.out.println("MyBeanFactoryPostProcessor...postProcessBeanFactory..."); // 这个时候我们所有的bean还没被创建
		                                                                              // 但是我们可以看一下通过Spring给我们传过来的这个beanFactory,我们能拿到什么
		int count = beanFactory.getBeanDefinitionCount(); // 我们能拿到有几个bean定义
		String[] names = beanFactory.getBeanDefinitionNames(); // 除此之外,我们还能拿到每一个bean定义的名字
		System.out.println("当前BeanFactory中有" + count + "个Bean");
		System.out.println(Arrays.asList(names));
	}
}

注意,我们自己编写的MyBeanFactoryPostProcessor类要想让Spring知道,并且还要能被使用起来,那么它一定就得被加到容器中,为此,我们可以在其上标注一个@Component注解。

然后创建一个配置类,例如ExtConfig,在该配置类上使用@ComponentScan注解来配置包扫描。

package com.meimeixia.ext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import com.meimeixia.bean.Blue;

@ComponentScan("com.meimeixia.ext")
@Configuration
public class ExtConfig {
	@Bean
	public Blue blue() {
		return new Blue();
	}	
}

package com.meimeixia.bean;

public class Blue {

	public Blue() {
		System.out.println("blue...constructor");
	}
	
	public void init() {
		System.out.println("blue...init...");
	}
	
	public void destory() {
		System.out.println("blue...destory...");
	}
}

编写测试类

package com.meimeixia.test;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.meimeixia.ext.ExtConfig;

public class IOCTest_Ext {
	
	@Test
	public void test01() {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(ExtConfig.class);
		// 关闭容器
		applicationContext.close();
	}
}

接下来测试下BeanFactoryPostProcessor的调用时机。

我们看到自己编写的BeanFactoryPostProcessor在Blue类的无参构造器创建Blue对象之前就已经工作了。我们看看到Blue组件注册到容器中的名字,只是此刻还没有创建对象。

说明BeanFactoryPostProcessor是在所有的bean定义信息都被加载之后才调用的。

源码分析

鼠标单击Eclipse左上角方法调用栈中的IOCTest_Ext.test01() line:12,这时程序来到了IOCTest_Ext类的test01方法中,如下图所示。

继续跟进代码,可以看到创建IOC容器时,最后还得刷新容器,如下图所示。

继续跟进代码,可以看到在刷新容器的过程中,还得执行在容器中注册的BeanFactoryPostProcessor(BeanFactory的后置处理器)的方法。

那具体是怎么来执行BeanFactoryPostProcessor的呢?我们继续跟进代码,发现又调用了一个invokeBeanFactoryPostProcessors方法,如下图所示。

下面我们来仔细分析一下PostProcessorRegistrationDelegate类中的invokeBeanFactoryPostProcessors方法具体都做了哪些操作。

会发现其遍历了所有的BeanFactoryPostProcessor组件,我们自己编写的实现了BeanFactoryPostProcessor接口的MyBeanFactoryPostProcessor类肯定也属于其中,所以会被遍历到,然后便会执行其postProcessBeanFactory方法。

小结

经过源码分析,我们可以得出这样一个结论:首先从IOC容器中找到所有类型是BeanFactoryPostProcessor的组件,然后再来执行它们其中的方法,而且是在初始化创建其他组件前面执行。

为什么在初始化其他组件前面执行的呢,之前我们分析AOP原理是,bean的初始化是放在finishBeanFactoryInitialization(beanFactory)方法执行的。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Java微信扫码登录功能并实现认证授权全过程

    Java微信扫码登录功能并实现认证授权全过程

    这篇文章主要给大家介绍了关于Java微信扫码登录功能并实现认证授权的相关资料,要在Java中实现微信扫码登录,您可以按照以下步骤进行操作,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2023-10-10
  • mybatis中xml之trim属性说明

    mybatis中xml之trim属性说明

    这篇文章主要介绍了mybatis中xml之trim属性说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-07-07
  • java的arrays数组排序示例分享

    java的arrays数组排序示例分享

    排序算法,基本的高级语言都有一些提供。C语言有qsort()函数,C++有sort()函数,java语言有Arrays类(不是Array)。用这些排序时,都可以写自己的排序规则
    2014-02-02
  • Spring MVC+FastJson+Swagger集成的完整实例教程

    Spring MVC+FastJson+Swagger集成的完整实例教程

    这篇文章主要给大家分享介绍了关于Spring MVC+FastJson+Swagger集成的完整实例教程,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧。
    2018-04-04
  • SpringBoot Cache缓存概念讲解

    SpringBoot Cache缓存概念讲解

    这篇文章主要介绍了Springboot cache缓存,使用缓存最关键的一点就是保证缓存与数据库的数据一致性,本文给大家介绍最常用的缓存操作模式,对Springboot cache缓存操作流程感兴趣的朋友一起看看吧
    2022-12-12
  • 你知道Java中的注解可以继承吗?

    你知道Java中的注解可以继承吗?

    注解想必大家都用过,也叫元数据,是一种代码级别的注释,可以对类或者方法等元素做标记说明。那么今天我想问大家的是类被继承了,注解能否继承呢?可能会和大家想的不一样,感兴趣的可以往下看
    2022-12-12
  • Ajax+Servlet+jsp显示搜索效果

    Ajax+Servlet+jsp显示搜索效果

    这篇文章主要为大家详细介绍了Ajax+Servlet+jsp显示搜索效果,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-12-12
  • java 数据类型有哪些取值范围多少

    java 数据类型有哪些取值范围多少

    这篇文章主要介绍了java 数据类型有哪些取值范围多少的相关资料,网上关于java 数据类型的资料有很多,不够全面,这里就整理下,需要的朋友可以参考下
    2017-01-01
  • 实例解析如何正确使用Java数组

    实例解析如何正确使用Java数组

    同一种类型数据的集合。其实数组就是一个容器。运算的时候有很多数据参与运算,那么首先需要做的是什么下面我们就一起来看看。
    2016-07-07
  • SpringCloud2020版本配置与环境搭建教程详解

    SpringCloud2020版本配置与环境搭建教程详解

    这篇文章主要介绍了SpringCloud2020版本配置与环境搭建教程详解,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-12-12

最新评论