如何基于环境动态加载Bean?Spring ImportSelector一招搞定

spring注入Bean的几种方式 阅读详情

01 引言

我们在使用一些Spring开关时,可能会发现导入的类很多都实现了org.springframework.context.annotation.ImportSelector接口,这个接口到底是干什么的?我们一起了解一下。

我们都知道,Spring的开关无非是控制Spring按需加载资源到容器中,或者通过开关加载启动类默认无法加载的资源。ImportSelector扮演者怎样的角色呢?

02 简介

ImportSelector 是 Spring 框架中一个非常强大的接口,位于 org.springframework.context.annotation 包下。它的核心作用是在运行时动态地选择一组配置类(即 @Configuration 类)或普通组件的全限定类名,并让 Spring 容器将它们导入并注册为 Bean 定义。

写过插件或者公用代码库的朋友都可能考虑过这样的问题。定义好的公用组件,肯定是独立的,可能会被引入到不同的模块项目中,其他项目默认不一定能扫描到自己的容器中。我们通常通过@Import手动导入或者配置到spring.factories中,以达到被加载的目的。

而今天要说的ImportSelector和Import的功能相同,但更具有灵活性,可以通过逻辑程序更加细粒度的控制资源的加载。可以把它理解为 “一个可以编程的、有逻辑的 @Import 注解”。

  • @Import 注解是静态的:必须在编译时就把要导入的配置类写在注解里。
  • ImportSelector 是动态的:它允许你根据当前的运行时环境(如:系统属性、环境变量、项目类路径、其他 Bean 的存在情况等)来决定到底要导入哪些配置。

通常情况下@Import和ImportSelector一起使用,通过@Import导入ImportSelector, 而 ImportSelector通过逻辑动态控制资源。

03 核心方法和工作原理

3.1 源码

selectImports方法时在Spring 3.1时才有的,而在Spring 5.2.4的新版本中有新增了getExclusionFilter,用来过滤不必要的资源。

3.2 方法说明

最主要的方法就是selectImports,用来导入所需要的资源信息。

AnnotationMetadata importingClassMetadata:

不得不说,Spring为参数取的名字非常有讲究,能够帮助我们理解其含义。importingClassMetadata表示导入类的元数据。如果你在 @Configuration /@Component修改的类(如:ExampleConfig.java)上使用了 @Import(MyImportSelector.class),那么这个 importingClassMetadata 对象就能让你获取到该配置类(ExampleConfig.java)上的所有注解信息(如 @Configuration 的属性,或者其他自定义注解)。

String[]:

方法需要返回一个由类的全限定名组成的字符串数组。这些类将会被 Spring 容器处理,就好像它们被直接写在 @Import 注解里一样。这些类通常就是 @Configuration 类,但也可以是任何需要被 Spring 管理的组件类(如标有 @Component, @Service 等的类)。

getExclusionFilter

是Predicate接口,对应的泛型是类的全限定名。

3.3 工作流程

  1. Spring 容器启动,解析一个配置类(比如 AppConfig)或启动类。
  2. 发现 AppConfig 上使用了 @Import(MyImportSelector.class)。
  3. 容器实例化 MyImportSelector。
  4. 调用 MyImportSelector.selectImports(...) 方法。
  5. MyImportSelector 根据自身的逻辑(检查环境等)计算出需要导入的类名数组。
  6. Spring 容器拿到这个数组,将这些类名对应的类进行解析、注册为 Bean 定义。
  7. 继续正常的启动流程

04 最佳实践

我们假设一个场景,我们根据不同的参数或者环境,加载不同的资源。这些资源默认不会被加载。

4.1 定义动态选择类

public class MyImportSelect implements ImportSelector, EnvironmentAware {

    private Environment environment;

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }

    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        System.out.println(importingClassMetadata.getClassName());
        String env = environment.getProperty("env");
        if (StringUtils.equalsIgnoreCase(env, "a")) {
            return new String[]{AConfig.class.getName()};
        }

        if (StringUtils.equalsIgnoreCase(env, "b")) {
            return new String[]{BConfig.class.getName()};
        }


        return new String[]{AConfig.class.getName(),
                BConfig.class.getName()};
    }

}

默认加载AConfig、BConfig,并根据不同的环境参数,加载不同的资源。

4.2 定义资源

@Component
public class AConfig {
    @Bean
    public A a() {
        return new A();
    }
}

public class A {
    public A() {
        System.out.println("A 被实例化了!");
    }
}

@Component
public class BConfig {

    @Bean
    public B b() {
        return new B();
    }
}

public class B {
    public B() {
        System.out.println("B 被实例化了!");
    }
}

4.3 定义开关

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(MyImportSelect.class)
public @interface EnableLoadBean {
    
}

这里的注解没有意义,只是一个开关。通过@Import导入MyImportSelect.class,当然也可以去掉开关,直接加在配置类上也可以。

4.4 打开开关

直接加在启动类上。

4.5 测试

增加启动参数:-Denv=a

我们可以看到生效了:

importingClassMetadata我们也打出来了,就是启动类。我们就可以获取启动类上的注解以及被继承的注解。

05 小结

ImportSelector 的核心优势在于它将配置选择逻辑从静态的注解或XML配置中解放出来,提供了运行时动态决策的能力。这使得应用程序能够更加灵活地适应不同的运行环境和需求变化。

在实际开发中,结合 @Conditional 系列注解和 ImportSelector,可以构建出高度可配置和可扩展的 Spring 应用程序。

Ubuntu 24.04.3 LTS 安装 OpenClaw 图文版 OpenClow安装指南 阅读详情

相关推荐

【RDMA】13. RDMA之用户态与内核态交互

原文:https://zhuanlan.zhihu.com/p/346708569 在“RDMA之Verbs”一文中我们说道,Verbs API分为用户态和内核态,分别以ibv_和ib_作为前缀。RDMA技术的最大的优势就在于用户态可以绕过内核,直接控制硬件收发数据,减少了系统调用和内存拷贝次数,所以大部分的RDMA应用都是用户态应用,即使用以ibv_为前缀的用户态Verbs API。 但是并非所有的用户态Verbs API都可以完全绕开内核,本文中我来讲解一下哪些API依赖于内核RDMA子系统(包括驱

我的笔记本 4285

【Spring】Bean加载控制

很多时候我们需要根据不同的条件在容器中加载不同的Bean,或者根据不同的条件来选择是否在容器中加载某个Bean,这就是Bean的加载控制,一般我们可以通过编程式或注解式两种不同的方式来完成Bean的加载控制

qq_50675319的博客 1593

Git Worktree + Claude Code:多终端并发开发完全实战

深入讲解如何使用 Git Worktree 配合多终端 Claude Code 实现并发开发,通过实战案例展示如何在 Android 开发中提升 2-3 倍效率,彻底告别等待 AI 的问题。

Cheson的专栏 1206

【Spring】Bean加载方式

registerBeanDefinitions方法的第一个参数和我们在上一种加载方式中使用过的annotationMetadata的作用是一样的,因此在这里我就不再过多介绍了,我们重点看第二个参数。第二个参数的类型是BeanDefinitionRegistry,光看名字我们知道了这是一个关于BeanDefinition的注册表,那么什么是BeanDefinition呢?这个其实涉及到spring比较底层的东西了,BeanDefinition实际上记录的是关于一个Bean的一系列信息,它包括但不限于:

qq_50675319的博客 2286

NFS服务器配置与autofs自动挂载

NFS服务器配置autofs自动挂载 环境: hostname ip OS server 192.168.220.138 centos7 client 192.168.220.139 centos7 一、NFS概述 NFS(Network File System)网络文件系统。最大功能就是通过网络,让不同的机器、不同的操作系统可以共享彼此的文件。 二、端口 [root@se...

DoloresOOO的博客 1027

STM32实战:增量式PID控制气体流量(附完整代码与调参技巧)

本文详细解析了如何在STM32平台上实现气体流量控制的增量式PID算法。内容涵盖从系统硬件架构选型、增量式PID算法原理与代码实现,到ADC采样滤波、PWM驱动配置等关键外设驱动,并提供了完整的参数整定技巧与工程调优实战指南,帮助开发者构建稳定可靠的气体流量控制系统。

rose2的博客 622

【Spring】八种常见Bean加载方式

本篇介绍了Spring中八种常见Bean的加载方式以及相关知识的补充

观止study 2978

CSAPP performance lab

CSAPP 深入理解计算机系统的performance Lab

weixin_46091531的博客 1253

【Spring】深入理解 Spring 中的 ImportSelector、Aware 和 Processor 接口

Spring 框架提供了一系列接口和机制,为开发者提供了灵活、可扩展的编程模型。其中,ImportSelector、Aware 接口以及 Processor 系列接口是非常重要的扩展点,本文将深入探讨它们的设计目的、使用方法以及示例应用。

DC1020的博客 1453

RK3588开发板NPU加速YOLO目标检测完整实战教程

🚀 RK3588开发板NPU加速YOLO目标检测实战 本文详细介绍了如何在瑞芯微RK3588开发板上利用内置NPU加速YOLO目标检测的全流程: 1️⃣ 环境准备:配置RKNPU2 SDK和aarch64交叉编译器,搭建Ubuntu开发环境 2️⃣ 模型转换:从ONNX格式转换为专用RKNN模型,适配NPU硬件特性 3️⃣ 性能对比:NPU推理将处理时间从833ms降至50ms以下,帧率提升16倍 4️⃣ 实战应用:支持图像/视频流/摄像头实时检测,提供完整编译和运行命令 关键优势:专为边缘AI设计的6T

FJN110的博客 931

乌鸦搜索算法(CSA)详解:从鸟类智能到优化引擎

乌鸦搜索算法(Crow Search Algorithm,CSA)是2016年由Askarzadeh等人提出的一种新型元启发式优化算法,该算法灵感来源于自然界中乌鸦群体的智能觅食行为。这一创新性算法已成为群体智能优化算法家族中的重要成员,与粒子群优化、遗传算法等传统算法相比,CSA具有原理新颖、参数设置简单、全局搜索能力强等特点。

qq_42212808的博客 1278

SpringBoot09-Bean的管理

bean的扫描、bean的注册:@Bean、@Import; 、注册条件:@ConditionalOnProperty、@ConditionalOnMissingBean、@ConditionalOnClass

qq_31532983的博客 1019

Qt Quick (QML) 老年人健康管理

通过 **Qt SQL** 模块将所有健康数据(用药记录、体检数据等)安全地存储在本地 **SQLite** 数据库中。你想用 **Qt C++** 结合 **Qt Quick** (QML) 来开发一个老年人健康管理软件,主要功能包含 **用药提醒** 和 **健康记录** (使用 `Qt SQL` 存储数据)。* **UI 框架**: Qt Quick (QML) - 用于构建流畅、动态的用户界面。**数据模型类 (models/MedicationReminder.h / .cpp)**

寒寒豆豆软件公司的博客 194

八种常见Bean加载方式

关于bean的加载方式,spring提供了各种各样的形式。已知类通过(类名.class)交给spring管理已知类名通过(类名字符串)并交给spring管理。两种形式内部其实都一样,都是通过spring的BeanDefinition对象初始化spring的bean。bean的定义由前期xml配置逐步演化成注解配置,本质是一样的,都是通过反射机制加载类名后创建对象,对象就是spring管控的bean。

meser88的博客 1536

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

Bean的加载方式

由于方式一种需要将spring管控的bean全部写在xml文件中,对于程序员来说非常不友好,所以就有了第二种方式。哪一个类要受到spring管控加载成bean,就在这个类的上面加一个注解,还可以顺带起一个bean的名字(id)。这里可以使用的注解有@Component以及三个衍生注解@Service、@Controller、@Repository。@Service当然,由于我们无法在第三方提供的技术源代码中去添加上述4个注解,因此当你需要加载第三方开发的bean的时候可以使用下列方式定义注解式的bean。

qq_54100648的博客 863

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

Spring 概念模型接口 ImportSelector : 配置类导入选择器

概述 在Spring中,如果想基于一个给定的选择标准(selection criteria),比如一个或者多个注解属性导入一些配置类(使用@Configuration的那些类)。可以实现接口ImportSelector来实现这样的逻辑。 一个ImportSelector实现类通常也可能会实现各种Aware接口,如果实现了这些Aware接口,这些接口方法的调用会发生在selectImports之前。...

Details Inside Spring 1545

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

Spring Bean注册的几种方式

前提:请在https://blog.youkuaiyun.com/dong19891210/article/details/105697175的情况下看 Spring bean有以下几种注册方式: 1. 通过GenericBeanDefinition注册 示例代码: 消息辅助类 public class Message { private String message; publi...

董广明的博客 1732

Spring高级之注解@Import注解、ImportSelector、ImportBeanDefinitionRegistrar详解(超详细)

定义/作用 @Import注解只能作用在类上,一种使用场景是在spring注解驱动开发环境下与配置类配合使用的,其作用是引用其他配置类。使得我们可以和早起的基于XML配置文件开发那样。使用不同的配置类配置不同的内容,比如Mysql数据源配置用一个配置类。Redis数据源配置用一个配置类等。然后使用在注解在一个主配置类中引入这些从配置类,使得配置更加清晰。被引入的类可以不使用@Configuration、@Component注解。 另一种使用 场景是该注解也是一种注册bean的方案。可以在配置类中使用Impo

qq_40837310的博客 3743

Spring原理-bean的加载控制方式

bena的加载控制指:根据特定情况对bean进行选择性加载以达到适用于项目的目标。

weixin_46926189的博客 180

spring注入Bean的八种方式

方式一 直接xml 注入 不举例了 方式二 配合包扫描@ComponentScan 使用@Controller @Service @Component 等方式注入 可以使用excludeFilters 排除扫描包下某些类 注意 在springboot应用下 默认扫描包位置 springboot启动类所在包及其子包 像图示这种情况下 F H这两个类 都被我加了 @Component 他们也在包扫描下的位置下 如果使用excludeFilters 可以排除某个类进容器 .

qq_41082092的博客 959

SpringBoot SpringBoot 原理篇 1 自动配置 1.11 bean 的加载控制【编程式】

SpringBoot SpringBoot 原理篇 1 自动配置 1.11 bean 的加载控制【编程式】

代码改变世界 655

Spring创建Bean的方式

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言 一、pandas是什么? 二、使用步骤 1.引入库 2.读入数据 总结 一、环境搭建 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XML..

qq_42236679的博客 224

Spring中对bean的管理

默认情况下,Spring项目启动时,会将bean对象都创建好放在IOC容器中,如果想要主动获取这些bean对象,首先注入IOC容器对象(ApplicationContext),根据需求获取对象。注:会受到作用域及延迟初始化的影响。

F190323X的博客 415

Spring几种引入Bean的方式

@Lazy懒加载

Lion_H的博客 1429

spring(一),注解实例化bean,@Configuration @Scope @Bean @ComponentScan @Lazy @Import ImportSelector @Condit

@注解实例化bean 欢迎使用Markdown编辑器 你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。 新的改变 我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几点新功能,帮助你用它写博客: 全新的界面设计 ...

qq_34811927的博客 358

Spring Bean四种注入方式(Springboot环境)

阅读此文建议参考本人写的Spring常用注解:https://blog.youkuaiyun.com/21aspnet/article/details/104042826 给容器中注册组件的四种方法: 1.@ComponentScan包扫描+组件标注注解@Component(@Controller@Service@Repository) 使用场景:自己写的代码,可以方便的加@Controller/@Se...

深度Java 2万+
上一篇: Archery:开源、一站式的数据库 SQL 审核与运维平台
下一篇: 安利一款 Redis 神器:Tiny RDM!颜值与实力并存
智_永无止境
博客等级 码龄10年 803粉丝 406原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

智_永无止境

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值