Spring控制Bean加载顺序的操作方法

 更新时间:2024年05月09日 14:25:53   作者:fuxing  
正常情况下,Spring 容器加载 Bean 的顺序是不确定的,那么我们如果需要按顺序加载 Bean 时应如何操作?本文将详细讲述我们如何才能控制 Bean 的加载顺序,需要的朋友可以参考下
(福利推荐:【腾讯云】服务器最新限时优惠活动,云服务器1核2G仅99元/年、2核4G仅768元/3年,立即抢购>>>:9i0i.cn/qcloud

(福利推荐:你还在原价购买阿里云服务器?现在阿里云0.8折限时抢购活动来啦!4核8G企业云服务器仅2998元/3年,立即抢购>>>:9i0i.cn/aliyun

前言

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

场景

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

  • FirstInitialization
  • SecondInitialization
  • ThirdInitialization
  • ForthInitialization

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

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

如何控制

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

使用@DependsOn 注解

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

@Component
public class FirstInitialization {

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

}
@Component
@DependsOn("firstInitialization")
public class SecondInitialization {

    @PostConstruct
    public void init(){
        System.out.println("我是第二个加载!");
    }

}
@Component
@DependsOn("secondInitialization")
public class ThirdInitialization {

    @PostConstruct
    public void init(){
        System.out.println("我是第三个加载!");
    }

}
@Component
@DependsOn("thirdInitialization")
public class ForthInitialization {

    @PostConstruct
    public void init(){
        System.out.println("我是第四个加载!");
    }

}

执行结果如下

基于 ApplicationContextInitializer 接口

接口简介

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

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

执行时机:

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

SpringBoot 执行run()方法前。

一般有什么用呢?

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

实现步骤

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

public class MyApplicationContextInitializer implements ApplicationContextInitializer {
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {

        //将自定义的BeanFactoryPostProcessor实现类保存到ApplicationContext中
        applicationContext.addBeanFactoryPostProcessor(new MyBeanFactoryPostProcessor());
    }
}

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

自定义BeanDefinitionRegistryPostProcessor

/**
 * BeanFactoryPostProcessor的子类
 * 允许开发人员在Bean定义注册之前和之后对BeanDefinition进行自定义处理,例如添加,修改或删除Bean定义等。
 */
public class MyBeanFactoryPostProcessor implements BeanDefinitionRegistryPostProcessor {

    // 初始化需要排序的类,这里要保证插入顺序只能用LinkedHashMap
    private 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);
        }
    };

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        Optional.ofNullable(ORDER_BEAN_MAP.keySet()).orElse(new HashSet<>()).stream()
                .forEach(beanName -> {
                    // 初始化一个 Bean 定义
                    AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder
                            .genericBeanDefinition().getBeanDefinition();

                    // 按顺序注册每个Bean
                    beanDefinition.setBeanClass(ORDER_BEAN_MAP.get(beanName));
                    registry.registerBeanDefinition(beanName, beanDefinition);
                });
    }
}

执行结果如下

以上就是Spring控制Bean加载顺序的操作方法的详细内容,更多关于Spring控制Bean加载顺序的资料请关注程序员之家其它相关文章!

相关文章

  • 基于SpringBoot应用监控Actuator安全隐患及解决方式

    基于SpringBoot应用监控Actuator安全隐患及解决方式

    这篇文章主要介绍了SpringBoot应用监控Actuator安全隐患及解决方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-07-07
  • springboot实现读取nacos配置文件

    springboot实现读取nacos配置文件

    这篇文章主要介绍了springboot实现读取nacos配置文件方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-09-09
  • java若依框架集成redis缓存详解

    java若依框架集成redis缓存详解

    今天小编就为大家分享一篇关于java若依框架集成redis缓存的实现,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2021-08-08
  • Java基于socket服务实现UDP协议的方法

    Java基于socket服务实现UDP协议的方法

    这篇文章主要介绍了Java基于socket服务实现UDP协议的方法,通过两个简单实例分析了java通过socket实现UDP发送与接收的技巧,需要的朋友可以参考下
    2015-05-05
  • java实现多线程交替打印

    java实现多线程交替打印

    这篇文章主要为大家详细介绍了java实现多线程交替打印,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-11-11
  • 一文详解Java中的动态填充Html模版并转PDF

    一文详解Java中的动态填充Html模版并转PDF

    在后端技术中,模板引擎和PDF生成工具是两个非常重要的领域,Thymeleaf和wkhtmltopdf是这两个领域的杰出代表,下面就来详细介绍一下Thymeleaf和wkhtmltopdf的技术特点吧
    2023-12-12
  • 基于Jenkins搭建.NET FrameWork持续集成环境

    基于Jenkins搭建.NET FrameWork持续集成环境

    这篇文章主要介绍了基于Jenkins搭建.NET FrameWork持续集成环境,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-08-08
  • SpringBoot+Redis使用AOP防止重复提交的实现

    SpringBoot+Redis使用AOP防止重复提交的实现

    本文主要介绍了SpringBoot+Redis使用AOP防止重复提交的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-07-07
  • java读取word-excel-ppt文件代码

    java读取word-excel-ppt文件代码

    OFFICE文档使用POI控件,PDF可以使用PDFBOX0.7.3控件,完全支持中文,用XPDF也行,不过感觉PDFBOX比较好,而且作者也在更新。水平有限,万望各位指正
    2009-04-04
  • java链表数据结构LinkedList插入删除元素时间复杂度面试精讲

    java链表数据结构LinkedList插入删除元素时间复杂度面试精讲

    这篇文章主要为大家介绍了java LinkedList插入和删除元素的时间复杂度面试精讲,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-10-10

最新评论

?


http://www.vxiaotou.com