首页 > 其他分享 >Spring如何控制Bean的加载顺序

Spring如何控制Bean的加载顺序

时间:2024-05-09 10:56:22浏览次数:20  
标签:顺序 Spring void public Bean class 加载

前言

正常情况下,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 {

    @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 容器刷新之前执行的一个回调函数。

执行时机:

  1. Spring 内部执行ConfigurableApplicationContext#refresh()方法前;
  2. 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,void,public,Bean,class,加载
From: https://www.cnblogs.com/fuxing/p/18181623

相关文章

  • 在SpringCloud2023中快速集成SpringCloudGateway网关
    你好,这里是codetrend专栏“SpringCloud2023实战”。本文主要简单介绍SpringCloud2023实战中SpringCoudGateway的搭建。后续的文章将会介绍在微服务中使用熔断Sentinel、鉴权OAuth2、SSO等技术。前言网关的选型不多,目前spring支持和维护的项目是SpringCloudGateway。Spring......
  • 美团二面:SpringBoot读取配置优先级顺序是什么?
    引言SpringBoot作为一种轻量级的Java应用程序框架,以其开箱即用、快速搭建新项目的特性赢得了广大开发者的青睐。其核心理念之一就是简化配置过程,使开发者能够快速响应复杂多变的生产环境需求。为了实现这一点,SpringBoot支持丰富的外部化配置机制,允许应用程序根据不同的部署环境......
  • 类加载器(ClassLoader)
    类加载器(ClassLoader)类加载、编译类加载器用于将Java类(此时的Java类指的是已经从.java编译成.class的字节码文件)通过JVM加载到内存中才能运行。编译java文件包名为:packagecom.melody.sec.classloader;、类名称为:DefineClassDemo编译java文件javaccom/melody/sec/class......
  • 解决SpringBoot内置tomcat出现error:An incompatible version [1.2.16] of the Apache
    问题描述在运行SpringBoot时出现一个error2024-05-08T20:52:06.512+08:00ERROR20752---[springboot3-003-demo][main]o.a.catalina.core.AprLifecycleListener:Anincompatibleversion[1.2.16]oftheApacheTomcatNativelibraryisinstalled,wh......
  • Spring SpringMVC——前端控制器初始化过程
     创建完DispatcherServlet对象时,会执行类中的init方法 如果不配置load-on-startup,那么DispatcherServlet将在第一次收到请求时才会被实例化和初始化。这意味着DispatcherServlet不会在服务器启动时立即执行创建和初始化的操作。当第一个请求到达时,Servlet容器(如Tomca......
  • 微服务Spring Cloud17_Feign9
    在前面的学习中,使用了Ribbon的负载均衡功能,大大简化了远程调用时的代码:如果就学到这里,你可能以后需要编写类似的大量重复代码,格式基本相同,无非参数不一样。有没有更优雅的方式,来对这些代码再次优化呢?这就是接下来要学的Feign的功能了。 一、简介Feign也叫伪装:Feign可以把Re......
  • spring刷题记录——to be continue
    在牛客网刷的题目,类似于补基础了?这里按照知识点进行分类,因为发现有些同样的知识点不同的题目还是很痛苦。这里就不用颜色标记了,因为我觉得都要记。Spring容器篇Spring容器也叫做Ioc容器(Ioc,在我之前写的随笔里面也有谈到),本质上就是一个工厂。Sp......
  • 微信小程序加载更多
    背景:博客小程序开发,涉及博客列表加载更多需求。前提:接口:https://abc.com/api/xx?pageSize=xx&page=xxview代码:<viewclass="container"><viewwx:for="{{items}}"wx:key="id"><text>{{item.cid}}--{{item.title}}</text>......
  • 微服务Spring Cloud17_熔断器Hystrix7
    一、简介Hystrix在英文里面的意思是豪猪,它的logo看下面的图是一头豪猪,它在微服务系统中是一款提供保护机制的组件,和eureka一样也是由netflix公司开发。主页:https://github.com/Netflix/Hystrix/ 那么Hystrix的作用是什么呢?具体要保护什么呢?Hystrix是Netflix开源的一......
  • docker - [15] springboot微服务打包docker镜像
    步骤:1、构建Springboot项目2、打包应用3、编写dockerfile4、构建docker镜像5、发布运行   一、构建Springboot项目(1)创建一个SpringBoot(以下这种方式对jdk版本有要求,可以创建一个Maven项目使用jdk8)(2)使用的SpringBoot版本是3.x,所以要求jdk17+(3)修改SpringBoot和jd......