Spring IoC学习之ApplicationContext中refresh过程详解

下面是关于“Spring IoC学习之ApplicationContext中refresh过程详解”的完整攻略。

前言

在使用Spring框架时,我们经常会用到ApplicationContext容器,并在容器初始化时调用refresh()方法来启动容器。那么这个过程中都做了些什么呢?本文将详细解析ApplicationContext容器的refresh()过程,帮助读者更好的理解Spring框架中实例化、属性注入、AOP、事务管理等方面的知识点。

refresh()方法概述

public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {

    ...

    @Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // 准备刷新容器
            prepareRefresh();

            // 准备Bean工厂
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // 设置Bean工厂的类加载器、后置处理器、属性编辑器等
            prepareBeanFactory(beanFactory);

            try {
                // 支持子类覆盖的方法,用于加载Bean定义,装配Bean组件
                postProcessBeanFactory(beanFactory);

                // 实例化并注入非懒加载的单例Bean对象
                invokeBeanFactoryPostProcessors(beanFactory);

                // 注册Bean后置处理器,通常用于Bean初始化前后的扩展操作
                registerBeanPostProcessors(beanFactory);

                // 初始化剩余非懒加载的Bean对象
                initMessageSource();

                // 初始化资源查找器
                initApplicationEventMulticaster();

                // 预留用于子类的扩展点,留待子类自行实现
                onRefresh();

                // 注册应用中的事件监听器
                registerListeners();

                // 实例化并初始化剩余的单例Bean对象
                finishBeanFactoryInitialization(beanFactory);

                // 完成刷新过程,通常包括清除缓存和发布容器生命周期事件
                finishRefresh();
            }

            catch (BeansException | RuntimeException ex) {
                destroyBeans();

                cancelRefresh(ex);

                throw ex;
            }
        }
    }

    ...

}

从上面的源码中可以看到refresh()方法的整个执行过程,可以分为以下几个步骤:

  1. 准备刷新容器。
  2. 准备Bean工厂。
  3. 设置Bean工厂的类加载器、后置处理器、属性编辑器等。
  4. 支持子类覆盖的方法,用于加载Bean定义,装配Bean组件。
  5. 实例化并注入非懒加载的单例Bean对象。
  6. 注册Bean后置处理器,通常用于Bean初始化前后的扩展操作。
  7. 初始化剩余非懒加载的Bean对象。
  8. 初始化资源查找器。
  9. 预留用于子类的扩展点,留待子类自行实现。
  10. 注册应用中的事件监听器。
  11. 实例化并初始化剩余的单例Bean对象。
  12. 完成刷新过程,通常包括清除缓存和发布容器生命周期事件。

下面将逐一介绍每一个步骤。

准备刷新容器

protected void prepareRefresh() {
    this.startupDate = System.currentTimeMillis();
    this.closed.set(false);
    this.active.set(true);

    if (logger.isInfoEnabled()) {
        logger.info("Refreshing " + this);
    }

    initPropertySources();

    this.environment.validateRequiredProperties();

    this.earlyApplicationEvents = new LinkedHashSet<>();

    if (this.earlyApplicationListeners == null) {
        this.earlyApplicationListeners = new LinkedHashSet<>(
                this.applicationListeners);
    }
    else {
        this.earlyApplicationListeners.addAll(this.applicationListeners);
    }

    this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(this.beanFactory);
    this.applicationEventMulticaster.setErrorHandler(new ErrorHandler() {
        @Override
        public void handleError(Throwable throwable) {
            if (throwable instanceof BeanCreationException) {
                BeanCreationException bce = (BeanCreationException) throwable;
                if (logger.isErrorEnabled() && bce.getBeanName() != null) {
                    logger.error("Error creating bean with name '" + bce.getBeanName() + "'", bce);
                }
            }
        }
    });

    // 留待容器刷新监听器进行处理
    this.refreshListeners.clear();
    addApplicationListener(new SourceFilteringListener(this, new RefreshListener()));

    // 如果用户没有配置BeanNameGenerator,则默认使用AnnotationBeanDefinitionParser
    if (this.beanNameGenerator == null) {
        this.beanNameGenerator = new AnnotationBeanNameGenerator();
    }

    // 如果没有默认的`ClassLoader`使用当前线程的`ClassLoader`
    if (this.resourceLoader == null) {
        this.resourceLoader = this;
    }
}

在刷新容器前准备工作主要包括以下内容:

  1. 设置容器的启动时间、关闭状态和活跃状态。
  2. 初始化属性源,如从环境中获取属性配置文件。
  3. 校验需要的属性是否配置完整。
  4. 初始化早期的ApplicationEventApplicationListener
  5. 初始化应用事件的广播器。
  6. 注册容器刷新监听器,并将其添加到广播器中。
  7. 设置默认的BeanNameGeneratorClassLoader

准备Bean工厂

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    refreshBeanFactory();
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    if (logger.isDebugEnabled()) {
        logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
    }
    return beanFactory;
}

准备Bean工厂包括刷新Bean工厂和获取Bean工厂,具体流程如下:

  1. 刷新Bean工厂。在这一步中会销毁原有的Bean工厂,读取新的Bean定义并将其装配成一个可用的Bean组件。
  2. 获取Bean工厂,该方法返回的就是我们最终的Bean工厂实例。

设置Bean工厂

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    // 添加占位符,避免因Bean依赖注入出错而导致应用启动失败
    beanFactory.addBeanPostProcessor(new BeanPostProcessor() {
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            return bean;
        }

        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            if (bean instanceof BeanFactoryAware) {
                ((BeanFactoryAware) bean).setBeanFactory(beanFactory);
            }
            return bean;
        }
    });

    // 设置类装载器
    if (!(beanFactory instanceof DefaultListableBeanFactory)) {
        return;
    }
    DefaultListableBeanFactory dlbf = (DefaultListableBeanFactory) beanFactory;
    dlbf.setAutowireCandidateResolver(new SimpleAutowireCandidateResolver(dlbf.getBeanClassLoader()));
    dlbf.setDependencyComparator(getDependencyComparator());
    Set<Object> seen = Collections.newSetFromMap(new ConcurrentHashMap<>(16));
    for (BeanFactoryPostProcessor postProcessor : getBeanFactoryPostProcessors()) {
        postProcessor.postProcessBeanFactory(dlbf);
    }
    if (!getBeanNamesForTypeIncludingAncestors(BeanFactoryPostProcessor.class, true, false).containsAll(this.beanFactoryPostProcessorSet)) {
        LinkedList<BeanFactoryPostProcessor> nonOrderedPostProcessors = new LinkedList<>();
        for (BeanFactoryPostProcessor postProcessor : getBeanFactoryPostProcessors()) {
            if (!this.beanFactoryPostProcessorSet.contains(postProcessor) && postProcessor instanceof PriorityOrdered) {
                nonOrderedPostProcessors.add(postProcessor);
            }
        }
        OrderComparator.sort(nonOrderedPostProcessors);
        this.beanFactoryPostProcessorList.addAll(nonOrderedPostProcessors);
    }
    for (BeanFactoryPostProcessor postProcessor : this.beanFactoryPostProcessorList) {
        postProcessor.postProcessBeanFactory(dlbf);
    }
    annoProcessor.setBeanFactory(beanFactory);
    for (Map.Entry<Class<?>, Object> entry : scopedBeans.entrySet()) {
        beanFactory.registerScope(entry.getKey().getName(), entry.getValue());
    }
    scopedBeans.clear();
    beanFactory.setTypeConverter(new StandardTypeConverter(beanFactory.getBeanClassLoader()));
    beanFactory.setTempClassLoader(null);

    // 注册自定义的属性编辑器
    beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
    beanFactory.addPropertyEditorRegistrar(new EnvironmentEditorRegistrar(getEnvironment(), getConversionService()));
}

设置Bean工厂主要包括以下内容:

  1. 添加占位符,避免因Bean依赖注入出错而导致应用启动失败。
  2. 设置类装载器。
  3. 注册BeanFactoryPostProcessor对象,用于在Bean工厂的属性值初始化之前对其进行额外的处理。(在这一步中也会为BeanFactoryPostProcessor对象找到对应的Bean定义,并利用反射来调用postProcessBeanDefinitionRegistry()方法,以进一步扩展我们的容器。)
  4. 注册自定义的属性编辑器。

加载Bean定义

protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    // 加载Bean定义
    // 数组的工厂名称已经预留出来了,为什么不用?直接调用这个方法。
    XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
    beanDefinitionReader.setEnvironment(this.getEnvironment());
    beanDefinitionReader.setResourceLoader(this);
    beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
    getBeanDefinitionRegistrars().forEach(registrar -> registrar.registerBeanDefinitions(this));
    getBeanDefinitionReaderListeners().forEach(listener -> beanDefinitionReader.addBeanDefinitionListener(listener));
    loadBeanDefinitions(beanDefinitionReader);
}

在这一步中会创建一个XmlBeanDefinitionReader对象,并填充容器。具体流程如下:

  1. 创建XmlBeanDefinitionReader对象,并为其设置环境参数和资源装载器等一系列属性。
  2. 从配置文件中读取Bean定义,利用BeanDefinition实例来保存这些定义。
  3. 将读取到的Bean定义向容器中填充,并进行合适的处理,如注入依赖的其他Bean、对属性进行设置等操作。

实例化并注入非懒加载的单例Bean对象

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    // 执行BeanFactoryPostProcessor的回调。通常包括Bean定义修改、Bean删减等操作
    List<BeanFactoryPostProcessor> regularPostProcessors =
            this.beanFactoryPostProcessorList.stream().filter(beanFactoryPostProcessor -> !(beanFactoryPostProcessor instanceof PriorityOrdered)).collect(Collectors.toList());
    List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
    for (BeanFactoryPostProcessor postProcessor : this.beanFactoryPostProcessorList) {
        if (postProcessor instanceof PriorityOrdered) {
            priorityOrderedPostProcessors.add(postProcessor);
        }
    }
    AnnotationAwareOrderComparator.sort(priorityOrderedPostProcessors);
    regularPostProcessors.addAll(priorityOrderedPostProcessors);
    for (BeanFactoryPostProcessor postProcessor : regularPostProcessors) {
        postProcessor.postProcessBeanFactory(beanFactory);
    }

    // 执行BeanDefinitionRegistryPostProcessor的回调
    List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
    for (BeanFactoryPostProcessor postProcessor : getBeanFactoryPostProcessors()) {
        if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
            currentRegistryProcessors.add((BeanDefinitionRegistryPostProcessor) postProcessor);
        }
    }
    List<BeanDefinitionRegistryPostProcessor> registryPostProcessors = new ArrayList<>();
    List<String> candidateNames = new ArrayList<>(beanFactory.getBeanDefinitionCount());
    candidateNames.addAll(Arrays.asList(beanFactory.getBeanDefinitionNames()));
    String[] processorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
    for (String procName : processorNames) {
        if (beanFactory.isTypeMatch(procName, PriorityOrdered.class)) {
            registryPostProcessors.add(beanFactory.getBean(procName, BeanDefinitionRegistryPostProcessor.class));
        }
        else if (beanFactory.isTypeMatch(procName, Ordered.class)) {
            currentRegistryProcessors.add(beanFactory.getBean(procName, BeanDefinitionRegistryPostProcessor.class));
        }
        else {
            registryPostProcessors.add(beanFactory.getBean(procName, BeanDefinitionRegistryPostProcessor.class));
        }
    }
    AnnotationAwareOrderComparator.sort(registryPostProcessors);
    currentRegistryProcessors.addAll(registryPostProcessors);
    Set<BeanDefinitionRegistryPostProcessor> processedBeans = new HashSet<>();
    for (BeanDefinitionRegistryPostProcessor postProcessor : currentRegistryProcessors) {
        postProcessor.postProcessBeanDefinitionRegistry(beanFactory);
        processedBeans.add(postProcessor);
    }
    currentRegistryProcessors.clear();

    // 实例化BeanFactoryPostProcessor类型的Bean并回调
    List<BeanFactoryPostProcessor> beanFactoryPostProcessors =
            new ArrayList<>(beanFactory.getBeansOfType(BeanFactoryPostProcessor.class, true, false).values());
    AnnotationAwareOrderComparator.sort(beanFactoryPostProcessors);
    for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
        postProcessor.postProcessBeanFactory(beanFactory);
    }
}

实例化并注入非懒加载的单例Bean对象主要包括以下内容:

  1. 执行BeanFactoryPostProcessor的回调。通常包括Bean定义修改、Bean删减等操作。
  2. 执行BeanDefinitionRegistryPostProcessor的回调。
  3. 实例化BeanFactoryPostProcessor类型的Bean并回调。

注册Bean后置处理器

protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
    for (String ppName : postProcessorNames) {
        if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
            BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
            this.priorityOrderedPostProcessors.add(pp);
        }
        else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
            BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
            this.orderedPostProcessors.add(pp);
        }
        else {
            BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
            this.nonOrderedPostProcessors.add(pp);
        }
    }
    List<BeanPostProcessor> orderedPostProcessorList =
            new ArrayList<>(this.priorityOrderedPostProcessors);
    // we must not include priorityOrderedPostProcessors here anymore
    orderedPostProcessorList.addAll(this.orderedPostProcessors);
    // guarantee order within merged processors, while keeping registration order for non-Ordered ones
    AnnotationAwareOrderComparator.sort(orderedPostProcessorList);
    for (BeanPostProcessor postProcessor : orderedPostProcessorList) {
        beanFactory.addBeanPostProcessor(postProcessor);
    }
    for (BeanPostProcessor postProcessor : this.nonOrderedPostProcessors) {
        beanFactory.addBeanPostProcessor(postProcessor);
    }
}

注册Bean后置处理器主要包括以下内容:

  1. 获取在容器中所有实现了BeanPostProcessor接口的实例Bean
  2. 按照BeanPostProcessor子类的Order顺序对Bean后置处理器进行排序。
  3. 注册Bean后置处理器。

初始化剩余非懒加载的Bean对象

```
protected void initMessageSource() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
// Make MessageSource aware of parent MessageSource.
if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
if (hms.getParentMessageSource() == null) {
// Only set parent context as parentMessageSource if no parent message source
// registered already.
hms.setParentMessageSource(getInternalParentMessageSource());
}
}
if (logger.isTraceEnabled()) {
logger.trace("Using MessageSource [" + this.messageSource + "]");
}
}
else {
// Use empty MessageSource to be able to accept getMessage calls.
DelegatingMessageSource dms = new DelegatingMessageSource();
dms.setParentMessageSource(getInternalParentMessageSource());
this.messageSource = dms;
beanFactory

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Spring IoC学习之ApplicationContext中refresh过程详解 - Python技术站

(0)
上一篇 2023年6月26日
下一篇 2023年6月26日

相关文章

  • 微信怎么查询注册时间?微信注册时间两种查询方法

    微信怎么查询注册时间? 微信是一款非常流行的社交媒体应用程序,许多人都想知道自己的微信注册时间。以下是两种查询微信注册时间的方法: 方法一:通过微信个人资料页面查询 打开微信应用程序并登录您的帐户。 在底部导航栏中,点击“我”选项卡,进入个人资料页面。 在个人资料页面上,向下滚动,直到找到“帐号与安全”部分。 点击“帐号与安全”部分下的“更多设置”选项。 在…

    other 2023年8月3日
    00
  • 微信开发者工具怎么开启多账号调试?微信开发者工具开启多账号调试教程

    下面是详细的攻略。 1. 准备工作 在使用微信开发者工具前,需要确保电脑上已经安装了微信开发者工具,并且拥有微信公众号或小程序的开发者账号。 2. 开启多账号调试 点击微信开发者工具顶部菜单栏的“设置”按钮。 在弹出的设置窗口中,点击“开发者工具设置”。 在“其他”选项卡中,勾选“允许多开调试”选项。 在“项目”选项卡中,打开你要调试的小程序或公众号项目,然…

    other 2023年6月26日
    00
  • js利用递归与promise 按顺序请求数据的方法

    下面是详细讲解 “JS利用递归与Promise按顺序请求数据的方法” 的完整攻略。 一、什么是递归 递归是一种算法思想,它通过反复调用自身,将问题转化为一个或多个小的同类问题来求解。在JS中,递归通常被用来解决树形结构或嵌套结构数据遍历问题。下面是一个简单的递归示例: function countdown(num) { console.log(num); i…

    other 2023年6月27日
    00
  • 关于sql:mysql-使用groupby和desc

    关于SQL: MySQL – 使用GROUP BY和DESC 在MySQL中,我们可以使用GROUP BY和DESC关键字来对查询结果进行组和排序。本攻略将详细介绍如何使用GROUP BY和DESC关键字。 问题描述 我们需要对MySQL数据库数据进行分组和排序。具体说,我们需要按照某个列的值进行分组,并按照另一个列的值进行降序。 解方法 要解决“使用GRO…

    other 2023年5月9日
    00
  • jpa自定义findall

    以下是关于JPA自定义findAll的完整攻略,包括基本知识和两个示例说明。 基本知识 在自定义findAll之前,您需要了解以下基本知识: JPA:Java Persistence API是Java EE的一个规范,它提供了一种将Java对象映射到关系数据库的方法。 JpaRepository:JpaRepository是Spring Data JPA提供…

    other 2023年5月7日
    00
  • JS继承之借用构造函数继承和组合继承

    JS继承之借用构造函数继承和组合继承 什么是继承? 在面向对象编程中,继承是指从一个类中派生出一个或多个新类的过程。派生类会继承父类的一些属性和方法,同时也可以有自己的一些属性和方法。 在JavaScript中,可以使用各种方式来实现继承,包括原型链继承、构造函数继承、组合继承、Class继承等。 借用构造函数继承 借用构造函数继承是指在子类构造函数中调用父…

    other 2023年6月26日
    00
  • C/C++实现投骰子游戏

    首先,我们需要确定投骰子游戏的规则和逻辑。 投骰子游戏通常由两个及以上玩家进行,每个玩家轮流投掷骰子,将骰子点数相加计算得分,总分数高者获胜。在每次投掷后,玩家可以选择停止投掷并计算得分,也可以继续投掷骰子。如果在投掷过程中出现了骰子点数之和等于7的情况,本轮该玩家得分清零。 基于这个规则,我们可以开始进行C/C++实现投骰子游戏的编写。 定义骰子点数范围和…

    other 2023年6月26日
    00
  • web压力测试工具(小而精)

    以下是关于“Java判断包含contains方法的使用”的完整攻略,包括基本概念、使用方法和两个示例。 基本概念 Java中的contains方法是用于判断一个字符串是否包含另一个字符串的方法。它返回一个布尔值,如果被查找的字符串包含指定的字符串,则返回true,否则返回false。contains方法是Java中常用的字符串操作方法之一,可以用于判断字符串…

    other 2023年5月7日
    00
合作推广
合作推广
分享本页
返回顶部