写点什么

spring 系列之 IOC 容器实例化过程五

作者:王威07325
  • 2023-05-29
    上海
  • 本文字数:3482 字

    阅读完需:约 11 分钟

refresh 中的 postProcessBeanFactory 和 invokeBeanFactoryPostProcessors

废话不多说,直接开始主题,今天我们讲解 refresh 的 postProcessBeanFactory invokeBeanFactoryPostProcessors 方法。



老规矩,贴上代码:


@Override  public void refresh() throws BeansException, IllegalStateException {    synchronized (this.startupShutdownMonitor) {      // Prepare this context for refreshing.      prepareRefresh();
// Tell the subclass to refresh the internal bean factory. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory);
try { // Allows post-processing of the bean factory in context subclasses. postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation. registerBeanPostProcessors(beanFactory);
// Initialize message source for this context. initMessageSource();
// Initialize event multicaster for this context. initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses. onRefresh();
// Check for listener beans and register them. registerListeners();
// Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event. finishRefresh(); }
catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); }
// Destroy already created singletons to avoid dangling resources. destroyBeans();
// Reset 'active' flag. cancelRefresh(ex);
// Propagate exception to caller. throw ex; }
finally { // Reset common introspection caches in Spring's core, since we // might not ever need metadata for singleton beans anymore... resetCommonCaches(); } } }
复制代码

1.postProcessBeanFactory

此方法允许子类在所有的 bean 尚未初始化之前注册 BeanPostProcessor。空实现且没有子类覆盖。



对,这个方法就是这么的简单,不要觉得它干了什么大事情,所以这篇文章,我们要讲解 refresh 的两个方法,当然重点就在下面讲解的方法中。

2.invokeBeanFactoryPostProcessors


实例化并调用所有已注册的 BeanFactoryPostProcessor bean,如果给出,请遵守显式顺序。 必须在单例实例化之前调用。


这个是 spring 对这个方法的一个定义,说大白话其实就是 BeanFactoryPostProcessor 接口允许我们在 bean 正是初始化之前改变其值。此接口只有一个方法:


void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory);
复制代码


有两种方式可以向 Spring 添加此对象:


  1. 通过代码的方式


context.addBeanFactoryPostProcessor
复制代码


  1. 通过 xml 配置的方式:


<bean class="base.SimpleBeanFactoryPostProcessor" />
复制代码


这里需要注意 BeanFactory 此时尚未进行 bean 的初始化工作,初始化是在后面的 finishBeanFactoryInitialization 进行的,所以在 BeanFactoryPostProcessor 对象中获取 bean 会导致提前初始化。


此方法的关键源码:


protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {    PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory,        getBeanFactoryPostProcessors());}
复制代码


getBeanFactoryPostProcessors 获取的就是 AbstractApplicationContext 的成员 beanFactoryPostProcessors(ArrayList),但是很有意思,只有通过 context.addBeanFactoryPostProcessor 这种方式添加的才会出现在这个 List 里,所以对于 xml 配置方式,此 List 其实没有任何元素。玄机就在 PostProcessorRegistrationDelegate 里。


核心思想就是使用 BeanFactory 的 getBeanNamesForType 方法获取相应的 BeanDefinition 的 name 数组,之后逐一调用 getBean 方法获取到 bean(初始化),getBean 方法后面再说。


注意此处有一个优先级的概念,如果你的 BeanFactoryPostProcessor 同时实现了 Ordered 或者是 PriorityOrdered 接口,那么会被首先执行。这其实在代码中就有体现


// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.//首先,调用实现了PriorityOrdered接口的BeanDefinitionRegistryPostProcessors       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();
// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered. //然后,调用实现了Ordered接口的BeanDefinitionRegistryPostProcessors 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();
// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear. // 最后调用其他的BeanDefinitionRegistryPostProcessors 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(); }
复制代码


其中 registryProcessor.postProcessBeanDefinitionRegistry(registry);这里需要稍微关注一下,这个跟 spring-context 中的 ConfigurationClassPostProcessor 等类有着紧密的联系。这里以后可以专门出一个专栏去讲解一下 spring-context。


好了,这两个方法已经讲解完毕,其中稍微提醒一下 invokeBeanFactoryPostProcessors 中很多的代码细节需要大家自己去琢磨,这里博主只讲解一个大概。

发布于: 刚刚阅读数: 4
用户头像

王威07325

关注

还未添加个人签名 2021-12-29 加入

还未添加个人简介

评论

发布
暂无评论
spring系列之IOC容器实例化过程五_spring ioc_王威07325_InfoQ写作社区