Spring控制bean加载顺序使用详解

 更新时间:2024年01月03日 11:15:58   作者:你还有牵挂吗  
在使用spring框架开发过程中,我们可能会遇到某个bean被另一个bean依赖,也就是bean-b的创建必须依赖bean-a等问题,类似这样的场景还有很多,总结来说,这就涉及到bean的加载顺序问题,如何解决呢,本文将给大家列举出几种常用的解决方案,需要的朋友可以参考下

1.误区

1.1 使用@Order注解去设置Ben的加载顺序(Order里面的数值越小优先级越高)

分别创建Config1,Config2

@Component
@Order(1)
public class Config1 {
    public Config1(){
        System.out.println("Config1构建了.........");
    }
}
 
​
@Component
@Order(2)
public class Config2 {
    public Config2(){
        System.out.println("Config2构建了.........");
    }
}
 
​

期间我还尝试着将@Component都改为使用@Configuration,结果仍然不变

总结:尝试过同包下,不同包下。最终测试结果为:一般情况下会按照SPring类的书写的顺序去创建,但是也不一定,最终其实得看你的编译出来的文件,的Class文件到底是什么样子的,包括操作系统文件的排序规则等一系列的因素。反正这个顺序是不确定的。如果包的顺序Config1在Config2的下面,就算Config1的@Order值小于Config2的值也没有用。

1.2使用@AutoConfigureAfter控制Ben的加载顺序(当前配置类在指定配置类之后执行)

@AutoConfigureBefore(当前配置类在指定配置类之前执行)

@AutoConfigureOrder(指定优先级,数值越小,优先级越高)

@Configuration
@AutoConfigureAfter(Config1.class)
public class Config2 {
    public Config2(){
        System.out.println("Config2构建了.........");
    }
}
 
@Configuration
public class Config1 {
    public Config1(){
        System.out.println("Config1构建了.........");
    }
}
@Configuration
@AutoConfigureAfter(Config1.class)
public class Config2 {
    public Config2(){
        System.out.println("Config2构建了.........");
    }
}
 
@Configuration
public class Config1 {
    public Config1(){
        System.out.println("Config1构建了.........");
    }
}
@Configuration
@AutoConfigureOrder(1)
public class Config2 {
    public Config2(){
        System.out.println("Config2构建了.........");
    }
}
 
@Configuration
@AutoConfigureOrder(2)
public class Config1 {
    public Config1(){
        System.out.println("Config1构建了.........");
    }
}

以上三个注解在同包和不同包都是不起作用的,和@Order是一样的也是通过书写顺序去创建的。

此时这里使用@Component是不起作用的,但是上面的@Order注解就不会有影响,无聊是使用@Configurantion还是@Component都是一个效果。

解决:在resources下新建META-INF/spring.factories文件

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.juzi.test.config.Config2,\
com.juzi.test.config.Config1

结果我就不粘出来了,感兴趣的小伙伴可以去尝试一下。

2.正确的控制方法

2.1使用@DependsOn("Bean B")注解控制(告诉Spring容器Bean B 应该被提前初始化)

创建AircraftTask、CarTask、TrainTask

目前创建的顺序是 Aircraft -> CarTask -> Train

 理想的创建顺序    Train -> Aircraft -> TrainCar

@Configuration
@DependsOn("trainTask")
public class AircraftTask {
    @PostConstruct
    public void init(){
        System.out.println("Aircraft获取Train存入redis的数据..........");
    }
}
 
@Configuration
@DependsOn("aircraftTask")
public class CarTask {
    @PostConstruct
    public void init(){
        System.out.println("CarTask获取到Aircraft的数据..........");
    }
}
 
@Configuration
public class TrainTask {
    @PostConstruct
    public void init(){
        System.out.println("Train初查询数据存入redis..........");
    }
}

结果:和理想的结果一致

但是如果像以上这种依赖的类数量过多的话这样写注解容易写错,我们可以使用以下方法 :

2.2使用BeanDefinitionRegistryPostProcessor和ApplicationContextInitializer去控制

对这两个类不是很熟悉的同学可以去下载Spring源码简单的阅读一下。

public class CarTask {
    @PostConstruct
    public void init(){
        System.out.println("CarTask获取到Aircraft的数据..........");
    }
}
 
public class AircraftTask {
    @PostConstruct
    public void init(){
        System.out.println("Aircraft获取Train存入redis的数据..........");
    }
}
 
public class TrainTask {
    @PostConstruct
    public void init(){
        System.out.println("Train初查询数据存入redis..........");
    }
}

这里不需要使用@Configuration或@Component注解,下面会对它们进行手动的添加到容器中。

public class MyBeanFactoryPostProcessor implements BeanDefinitionRegistryPostProcessor {
 
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        AbstractBeanDefinition beanDefinition2 = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
        beanDefinition2.setBeanClass(TrainTask.class);
        registry.registerBeanDefinition("trainTask",beanDefinition2);
 
        AbstractBeanDefinition beanDefinition1 = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
        beanDefinition1.setBeanClass(AircraftTask.class);
        registry.registerBeanDefinition("aircraftTask",beanDefinition1);
 
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
        beanDefinition.setBeanClass(CarTask.class);
        registry.registerBeanDefinition("carTaskTask",beanDefinition);
        //相当于往Spring容器初始化的时的那个List里面添加了一个Bean 只要在扫描之前执行了postProcessBeanDefinitionRegistry 方法 那么就会安装List里面存放的顺序
        //生成Bean
    }
 
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
 
    }
}
public class MyApplicationContextInitiaLizer implements ApplicationContextInitializer {
 
    @Override
    public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
        configurableApplicationContext.addBeanFactoryPostProcessor(new MyBeanFactoryPostProcessor());
    }
}

resources下新建META-INF/spring.factories文件 配置MyApplicationContextInitiaLizer的全限定类名即可。

#org.springframework.context.ApplicationContextInitializer=com.example.demo11.config.MyApplicationContextInitiaLizer

结果:也和预期的一致

以上就是Spring控制bean加载顺序使用详解的详细内容,更多关于Spring控制bean加载顺序的资料请关注脚本之家其它相关文章!

相关文章

  • springcloud client指定注册到eureka的ip与端口号方式

    springcloud client指定注册到eureka的ip与端口号方式

    这篇文章主要介绍了springcloud client指定注册到eureka的ip与端口号方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-03-03
  • 在 Spring Boot 中使用异步线程时的 HttpServletRequest 复用问题记录

    在 Spring Boot 中使用异步线程时的 HttpServletReque

    文章讨论了在SpringBoot中使用异步线程时,由于HttpServletRequest复用导致的Cookie解析失败问题,为了解决这个问题,文章推荐了使用HttpServletRequestWrapper创建请求副本、手动传递请求上下文和延迟请求清理等方法,感兴趣的朋友一起看看吧
    2025-03-03
  • HashMap工作原理_动力节点Java学院整理

    HashMap工作原理_动力节点Java学院整理

    这篇文章主要介绍了HashMap工作原理_动力节点Java学院整理,需要的朋友可以参考下
    2017-04-04
  • Java实现一键生成表controller,service,mapper文件

    Java实现一键生成表controller,service,mapper文件

    这篇文章主要为大家详细介绍了如何利用Java语言实现一键生成表controller,service,mapper文件,文中的示例代码讲解详细,需要的可以收藏一下
    2023-05-05
  • Spring Batch实战示例

    Spring Batch实战示例

    批量数据处理是一个非常常见的需求,比如月底的工资代发、银行对账、数据报表生成等,当数据量达到几十万甚至上百万时,可以高效的完成,感兴趣的可以了解一下
    2026-02-02
  • SpringBoot实现IP限流的示例代码

    SpringBoot实现IP限流的示例代码

    在高并发的互联网应用中,系统稳定性面临严峻挑战,爬虫、以及不合理的接口调用都可能导致系统资源耗尽,影响正常用户体验,为了保障系统的稳定性和可用性,本文将深入探讨如何在 Spring Boot 中实现 IP 限流,需要的朋友可以参考下
    2025-06-06
  • Spring之关于PropertyDescriptor的扩展剖析

    Spring之关于PropertyDescriptor的扩展剖析

    这篇文章主要介绍了Spring之关于PropertyDescriptor的扩展剖析,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-07-07
  • Spring AOP注解配置与XML配置双实战教程

    Spring AOP注解配置与XML配置双实战教程

    本文详细介绍了面向切面编程(AOP)的概念、快速入门、核心概念、切点确定、通知分类、获取被增强方法相关信息、应用案例、XML配置、多切面顺序问题以及AOP原理中的动态代理,通过实例展示了如何在Spring框架中使用AOP进行方法增强,感兴趣的朋跟随小编一起看看吧
    2025-11-11
  • Java经典面试题最全汇总208道(三)

    Java经典面试题最全汇总208道(三)

    这篇文章主要介绍了Java经典面试题最全汇总208道(三),本文章内容详细,该模块分为了六个部分,本次为第三部分,需要的朋友可以参考下
    2023-01-01
  • SpringBoot项目启动时如何将需要数据添加到redis缓存

    SpringBoot项目启动时如何将需要数据添加到redis缓存

    文章介绍了使用Java注解@PostConstruct进行项目启动时加载,并使用Spring和Redis进行数据缓存的操作,通过`setCacheObject`方法将数据存储到Redis中,并提供了清空缓存的方法
    2026-04-04

最新评论