Spring如何控制Bean的加载顺序

news/2024/10/22 12:14:19/

前言

正常情况下,Spring 容器加载 Bean 的顺序是不确定的,那么我们如果需要按顺序加载 Bean 时应如何操作?本文将详细讲述我们如何才能控制 Bean 的加载顺序。


场景

我创建了 4 个 Class 文件,分别命名为

  1. FirstInitialization

  2. SecondInitialization

  3. ThirdInitialization

  4. ForthInitialization

我希望这 4 个类按照 1、2、3、4 的顺序加载。

如下图,直接加载的话,顺序是 1、4、2、3,并不能达到要求。

如何控制

注意:网上很多文章说Order注解或Ordered接口可以控制 Bean 的加载顺序,其是并不能,它们的作用是定义 Spring IOC 容器中 Bean 定义类的执行顺序的优先级,并不是定义加载顺序。

使用@DependsOn 注解

在需要调整顺序的类上依次加@DependsOn注解,缺点是类过多的时候需要一个个加注解,且不好维护

@Component
public class FirstInitialization {@PostConstructpublic void init(){System.out.println("我是第一个加载!");}}

@Component
@DependsOn("firstInitialization")
public class SecondInitialization {@PostConstructpublic void init(){System.out.println("我是第二个加载!");}}

@Component
@DependsOn("secondInitialization")
public class ThirdInitialization {@PostConstructpublic void init(){System.out.println("我是第三个加载!");}}

@Component
@DependsOn("thirdInitialization")
public class ForthInitialization {@PostConstructpublic void init(){System.out.println("我是第四个加载!");}}

执行结果如下

基于 ApplicationContextInitializer 接口

接口简介

这里我简单介绍一个这个接口的用处, 等到整理到相关源码的时候再详细介绍。

ApplicationContextInitializer接口是在 Spring 容器刷新之前执行的一个回调函数。

执行时机:

  1. Spring 内部执行ConfigurableApplicationContext#refresh()方法前;

  2. SpringBoot 执行run()方法前。

一般有什么用呢?

在 SpringBoot 应用中 Classpath 上会有很多 jar 包,有些 jar 包需要在refresh()调用前对应用上下文做一些初始化动作,因此会提供ApplicationContextInitializer接口的实现类,放在如下图的文件中,这样会被SpringApplication#initialize发现,然后完成对应初始化。

实现步骤

首先创建一个类继承ApplicationContextInitializer接口。

public class MyApplicationContextInitializer implements ApplicationContextInitializer {@Overridepublic void initialize(ConfigurableApplicationContext applicationContext) {//将自定义的BeanFactoryPostProcessor实现类保存到ApplicationContext中applicationContext.addBeanFactoryPostProcessor(new MyBeanFactoryPostProcessor());}
}

创建`META-INF/spring.factories`文件。

自定义`BeanDefinitionRegistryPostProcessor`。

/*** BeanFactoryPostProcessor的子类* 允许开发人员在Bean定义注册之前和之后对BeanDefinition进行自定义处理,例如添加,修改或删除Bean定义等。*/
public class MyBeanFactoryPostProcessor implements BeanDefinitionRegistryPostProcessor {// 初始化需要排序的类,这里要保证插入顺序只能用LinkedHashMapprivate static final Map<String, Class> ORDER_BEAN_MAP = new LinkedHashMap<>() {{put("firstInitialization", FirstInitialization.class);put("secondInitialization", SecondInitialization.class);put("thirdInitialization", ThirdInitialization.class);put("forthInitialization", ForthInitialization.class);}};@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {Optional.ofNullable(ORDER_BEAN_MAP.keySet()).orElse(new HashSet<>()).stream().forEach(beanName -> {// 初始化一个 Bean 定义AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();// 按顺序注册每个BeanbeanDefinition.setBeanClass(ORDER_BEAN_MAP.get(beanName));registry.registerBeanDefinition(beanName, beanDefinition);});}
}

执行结果如下

文章转载自:fuxing.

原文链接:https://www.cnblogs.com/fuxing/p/18181623

体验地址:引迈 - JNPF快速开发平台_低代码开发平台_零代码开发平台_流程设计器_表单引擎_工作流引擎_软件架构


http://www.ppmy.cn/news/1459447.html

相关文章

如何使用dockerfile文件将项目打包成镜像

要根据Dockerfile文件来打包一个Docker镜像&#xff0c;你需要遵循以下步骤。这里假设你已经安装了Docker环境。 1. 准备Dockerfile 确保你的Dockerfile文件已经准备就绪&#xff0c;并且位于你希望构建上下文的目录中。Dockerfile是一个文本文件&#xff0c;包含了用户可以调…

美股订单类型有哪些

美股交易中&#xff0c;订单类型是投资者执行交易指令的重要工具。了解不同类型的订单&#xff0c;可以帮助投资者制定更有效的交易策略&#xff0c;并控制风险。 1. 市价单&#xff1a;快速成交&#xff0c;不惧踏空 市价单&#xff08;Market Order&#xff09;是一种以当时…

日常java选择题

目录 题目 题目 来自牛客网 1.下面代码输出结果是? int i 5; int j 10; System.out.println(i ~j); A.Compilation error because" ~" doesnt operate on integers B.-5 C.-6 D.15 解析&#xff1a;这段代码的目的是通过位运算符~来反转j的位&#xff0c;然…

探索Python循环:索引值的获取与应用

在Python编程中&#xff0c;我们经常需要在循环中使用索引值来访问列表、元组或其他序列类型的元素。本文将详细讲解如何在’for’循环中访问索引值&#xff0c;并提供示例代码及运行结果&#xff0c;帮助初学者更好地理解和应用这一概念。 基本原理 在Python中&#xff0c;f…

局域网手机端远程控制手机

局域网手机端远程控制手机 随着科技的进步和智能设备的普及&#xff0c;远程控制技术在日常生活与工作中的应用越来越广泛。其中&#xff0c;局域网内的手机端远程控制手机技术&#xff0c;因其便捷性和实用性&#xff0c;受到了众多用户的关注。本文将简要介绍该技术及其应用…

STM32_HAL_RTC_中断实现闹钟

1STM32设置 在STM32Cude中设置RTC//具体设置看先前发的文章 再打开闹钟中断&#xff08;如下图&#xff09; 2代码思路 2.1启动闹钟&#xff08;HAL_RTC_SetAlarm_IT(&hrtc,&sAlarm,FORMAT_BCD)&#xff09; 2.2设置回调函数&#xff08;void HAL_RTC_AlarmAEventC…

论文阅读-THE GENERALIZATION GAP IN OFFLINE REINFORCEMENT LEARNING(ICLR 2024)

1.Motivation 本文希望比较online RL、offline RL、序列决策和BC等方法的泛化能力(对于不同的初始状态、transition functions、reward functions&#xff0c;现阶段offline RL训练的方式都是在同一个环境下的数据集进行训练)。实验发现offline的算法相较于online算法对新环境…

Ansible自动化运维工具单模块介绍

前言 自动化运维是指利用自动化工具和技术来简化、自动化和优化IT基础设施的管理和运维过程&#xff0c;从而提高效率、降低成本&#xff0c;并减少人为错误。在当今复杂的IT环境中&#xff0c;自动化运维已经成为许多组织和企业提高生产力和保证系统稳定性的重要手段。Ansibl…