从零开始学spring源码之ioc预热:bean的拓展和beanProcessor注册

时间:2022-09-30 11:28:38

上篇聊完了bean的解析,说起来做的事情很简单,把xml文件里面配置的标签全部解析到spring容器里面,但是spring做的时候,花了那么大代价去做,后面看看到底值不值得呢。

接下来看看prepareBeanFactory(beanFactory)方法,点进去看一下:

public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {

// Invoke BeanDefinitionRegistryPostProcessors first, if any.
Set<String> processedBeans = new HashSet<>();

if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();

for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryProcessor =
(BeanDefinitionRegistryPostProcessor) postProcessor;
registryProcessor.postProcessBeanDefinitionRegistry(registry);
registryProcessors.add(registryProcessor);
}
else {
regularPostProcessors.add(postProcessor);
}
}

// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the bean factory post-processors apply to them!
// Separate between BeanDefinitionRegistryPostProcessors that implement
// PriorityOrdered, Ordered, and the rest.
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

//1.调用实现了PriorityOrdered 的BeanDefinitionRegistryPostProcessors
// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();

//2.调用实现了Ordered 的BeanDefinitionRegistryPostProcessors
// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();

//3.调用其他剩余的BeanDefinitionRegistryPostProcessors
// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
boolean reiterate = true;
while (reiterate) {
reiterate = false;
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
reiterate = true;
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
}

//4.调用所有实现了BeanFactoryPostProcessor类并重写了postProcessBeanFactory方法的回调
// Now, invoke the postProcessBeanFactory callback of all processors handled so far.
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
}

else {
// Invoke factory processors registered with the context instance.
invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
}

// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the bean factory post-processors apply to them!
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);

// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
// Ordered, and the rest.
List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
if (processedBeans.contains(ppName)) {
// skip - already processed in first phase above
}
else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}

// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

// Next, invoke the BeanFactoryPostProcessors that implement Ordered.
List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();
for (String postProcessorName : orderedPostProcessorNames) {
orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
sortPostProcessors(orderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);

// Finally, invoke all other BeanFactoryPostProcessors.
List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
for (String postProcessorName : nonOrderedPostProcessorNames) {
nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);

// Clear cached merged bean definitions since the post-processors might have
// modified the original metadata, e.g. replacing placeholders in values...
beanFactory.clearMetadataCache();
}

我的天哪,又是这么长的代码,仔细一看,好多重复的代码,这块重复的代码封装一下是不是很完美(小声bb),仔细分析之后(主要还是靠之前的大牛们写的博客),其实做的主要就是4件事:

1.调用实现了PriorityOrdered 的BeanDefinitionRegistryPostProcessors
2.调用实现了Ordered 的BeanDefinitionRegistryPostProcessors
3.调用其他剩余的BeanDefinitionRegistryPostProcessors
4.调用所有实现了BeanFactoryPostProcessor类并重写了postProcessBeanFactory方法的回调
我们首先看前三步调用的BeanDefinitionRegistryPostProcessors是在干啥,核心代码其实就是上面标红的代码,点进去:
private static void invokeBeanDefinitionRegistryPostProcessors(
Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) { for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
postProcessor.postProcessBeanDefinitionRegistry(registry);
}
}

这块只做了一个遍历,然后调用postProcessBeanDefinitionRegistry方法,这个方法又是干啥的呢,点进去是一个抽象类,我们先不管这个是干嘛的,看一下我写的一个类:

@Component
public class BeanDefinitionTest implements BeanDefinitionRegistryPostProcessor {

@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
genericBeanDefinition.setBeanClass(BeanClass.class);

// genericBeanDefinition.getConstructorArgumentValues().addGenericArgumentValue(null);

MutablePropertyValues propertyValues = genericBeanDefinition.getPropertyValues();
propertyValues.addPropertyValue("username","peter");

registry.registerBeanDefinition("beanClass",genericBeanDefinition);

}

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println(beanFactory.getBean("beanClass"));
}
}

可以看到BeanDefinitionTest实现了 BeanDefinitionRegistryPostProcessor ,我重写了BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法和BeanFactoryPostProcessor的postProcessBeanFactory方法,你会发现其实上面前3步调用的方法和第4步调用的方法,就是我这边重写的两个方法,感兴趣的同学可以自己写一下,启动容器的时候debug看看。那么这两个方法是做什么的呢,不知道还记不记得前面注册beanDefinition的时候,其实就是用BeanDefinitionRegistry 注册的。而beanFactory是存储所有beanDefinition对象的容器,拿到它就相当于拿到了所有的beanDefinition对象。好像还是很厉害的,实现了这一个方法,既可以添加自定义的bean,又可以自己修改已经有的bean对象,spring大法牛逼。

接下来再看一下beanPostProcessor的注册:

public static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {

String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);

// Register BeanPostProcessorChecker that logs an info message when
// a bean is created during BeanPostProcessor instantiation, i.e. when
// a bean is not eligible for getting processed by all BeanPostProcessors.
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));

// Separate between BeanPostProcessors that implement PriorityOrdered,
// Ordered, and the rest.
List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
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);
}
}

//1.注册实现了PriorityOrdered的beanPostProcessor
// First, register the BeanPostProcessors that implement PriorityOrdered.
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);

//2.注册实现了Ordered的beanPostProcessor
// Next, register the BeanPostProcessors that implement Ordered.
List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>();
for (String ppName : orderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
orderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
sortPostProcessors(orderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, orderedPostProcessors);

//3.注册没用实现排序的beanPostProcessor
// Now, register all regular BeanPostProcessors.
List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
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.重新注册所有的的beanPostProcessor
// Finally, re-register all internal BeanPostProcessors.
sortPostProcessors(internalPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, internalPostProcessors);

// Re-register post-processor for detecting inner beans as ApplicationListeners,
// moving it to the end of the processor chain (for picking up proxies etc).
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}

主要还是分为4步:

1.注册实现了PriorityOrdered的beanPostProcessor

2.注册实现了Ordered的beanPostProcessor

3.注册没有实现排序接口的beanPostProcessor

4.重新注册所有的的beanPostProcessor

而注册的具体逻辑又分为几步:

1.getBean获取BeanProcessor实例

2.加入容器

3.排序后注册

在这里,很多我们后面aop或者其他地方需要用的到处理器类就都已经实例化完成了,刚开始接触的时候都说这叫bean的后置处理器,因此,一直纠结于在bean实例化完成后才会去执行,可实际研究源码的时候,发现并不是我想的这样,因此困扰了很久。

其实就是一个处理器类吧,在bean初始化前后都会去调用,让我们自己去做一些定制化的修改,而且可以实现排序接口,实现执行的先后顺序。

总结:

        刚开始接触spring源码的时候,这块的源码总是无法理解,因为脑子里面的固有思维是spring做的肯定是去加载,注册,实例化bean的,对于框架的拓展性,高可用没有什么概念,像这个方法里面基本上除了为了提前能调用到我添加的类,会去调用getBean方法提前实例化,其他的基本都是为了让使用者可以更*的去拓展。我想,以后在我自己去写代码的时候,也会去多考虑这些吧。

从零开始学spring源码之ioc预热:bean的拓展和beanProcessor注册的更多相关文章

  1. 从零开始学spring源码之xml解析&lpar;一&rpar;:入门

    谈到spring,首先想到的肯定是ioc,DI依赖注入,aop,但是其实很多人只是知道这些是spring核心概念,甚至不知道这些代表了什么意思,,作为一个java程序员,怎么能说自己对号称改变了jav ...

  2. 从零开始学spring源码之xml解析&lpar;二&rpar;:默认标签和自定义标签解析

    默认标签: 上一篇说到spring的默认标签和自定义标签,发现这里面东西还蛮多的.决定还是拆开来写.今天就来好好聊聊这两块是怎么玩的,首先我们先看看默认标签: private void parseDe ...

  3. spring源码浅析——IOC

    =========================================== 原文链接: spring源码浅析--IOC   转载请注明出处! ======================= ...

  4. spring源码分析---IOC&lpar;1&rpar;

    我们都知道spring有2个最重要的概念,IOC(控制反转)和AOP(依赖注入).今天我就分享一下spring源码的IOC. IOC的定义:直观的来说,就是由spring来负责控制对象的生命周期和对象 ...

  5. Spring源码解析-ioc容器的设计

    Spring源码解析-ioc容器的设计 1 IoC容器系列的设计:BeanFactory和ApplicatioContext 在Spring容器中,主要分为两个主要的容器系列,一个是实现BeanFac ...

  6. 【Spring源码分析】原型Bean实例化过程、byName与byType及FactoryBean获取Bean源码实现

    原型Bean加载过程 之前的文章,分析了非懒加载的单例Bean整个加载过程,除了非懒加载的单例Bean之外,Spring中还有一种Bean就是原型(Prototype)的Bean,看一下定义方式: & ...

  7. Spring 源码学习 - 单例bean的实例化过程

    本文作者:geek,一个聪明好学的同事 1. 简介 开发中我们常用@Commpont,@Service,@Resource等注解或者配置xml去声明一个类,使其成为spring容器中的bean,以下我 ...

  8. Spring源码:IOC原理解析(一)

    版权声明:本文为博主原创文章,转载请注明出处,欢迎交流学习! IOC(Inversion of Control),即控制反转,意思是将对象的创建和依赖关系交给第三方容器处理,我们要用的时候告诉容器我们 ...

  9. Spring源码:IOC原理解析(二)

    版权声明:本文为博主原创文章,转载请注明出处,欢迎交流学习! 接着上一章节的内容,我们来分析当new一个FileSystemXmlApplicationContext对象的时候,spring到底做了那 ...

随机推荐

  1. html5遵循的5个设计原则

    前面的话 实际上,html5并不是由w3c直接制定的,w3c的方向是xhtml2,而不是html5.当xhtml2脱离现实,无法付诸实践时,w3c工作组才将研究方向转向html5.为什么xhtml2从 ...

  2. Node&period;js高级编程读书笔记 - 5 数据库 - Never

    Outline 6 连接数据库 6.1 使用node-mysql连接MySQL数据库 6.2 使用Nano连接CouchDB数据库 6.3 使用Mongoose连接MongoDB数据库 6 连接数据库 ...

  3. &lbrack;转&rsqb;Unity&colon; make your lists functional with ReorderableList

    原文地址:http://va.lent.in/unity-make-your-lists-functional-with-reorderablelist/ This article is reprod ...

  4. 使用Xamarin在Visual Studio中开发Android应用

    原文:使用Xamarin在Visual Studio中开发Android应用 本文使用的环境是Windows 8 Visual Studio 2012.2 1.下载Xamarin http://xam ...

  5. 3月题外:关于JS实现图片缩略图效果的一些小问题

    由于3月可能要结束实习,所以应该不会有特别固定的主题,另外我会在月初陆续补上上个月的番外篇Projection和TMS,作为介绍性的内容对矢量切片部分进行补充,剩下时间不定期写一些杂烩. 最近两天在做 ...

  6. adb 获取Android手机信息命令&lpar;1&rpar;

    @set version=1.7.2Normal @echo ============================================================= @echo I ...

  7. 简化的CDN架构分析

    CDN架构的设计目标是通过复制系统资源(即Web服务器)的方式来获得高性能和高扩展性,为了能确保在海量内容下可以稳定提供高性能的服务.系统资源的复制可以在本地和地理两个尺度上进行.如果是本地复制则响应 ...

  8. file&lowbar;get&lowbar;contents函数不能使用的解决方法

    今天开发微信公众平台的时候 使用file_get_contents 去获得token 结果一直返回false.百度了一下,大部分都是说用curl 偶然发现可能是openssl没有开启的问题,开启ope ...

  9. 汉化DevExpress

    现在的DevExpress组件包提供了TcxLocalizer,拖一个放到Form上. 然后设置相关的属性: 即可完成汉化了!怎么样,够简单!!! 需要DevChs.ini文件的朋友,点击链接加入群聊 ...

  10. echarts4的学习

    echarts的学习 1.echarts的全解注释.https://www.2cto.com/kf/201708/665624.html ### 2.从echarts3开始学习echarts源码.ht ...