SpringBoot自动装配原理之@Import注解解析

文章目录

  • 1. 概述
  • 2. 使用
    • 2.1 导入普通Bean
    • 2.2 导入配置类
    • 2.3 导入 ImportSelector 实现类
    • 2.4 导入 ImportBeanDefinitionRegistrar 实现类
  • 3. 区别


在这里插入图片描述

在这里插入图片描述


1. 概述

当谈及现代Java开发领域中的框架选择时,SpringBoot无疑是无与伦比的热门之选。其简化了开发流程,提高了效率,同时保持了可靠性和可维护性。在这个充满活力的生态系统中,@Import注解闪耀着独特的光芒。它不仅仅是一个普通的注解,更是一个强大的工具,为我们提供了一种优雅而灵活的方式来管理组件的装配和配置。本文将带您深入探究@Import注解的内涵,揭示其背后的原理和机制,助您在SpringBoot项目中游刃有余地应用这一技术,从而让您的应用更加强大、灵活和易于扩展。让我们一起踏上这场关于@Import注解的探索之旅,探索其奥秘,挖掘其潜力!


Spring 提供的@Import 注解: 使用@Import导入的类会被Spring加载到 IOC 容器中, 有四种用法:

  1. 导入Bean
  2. 导入配置类
  3. 导入 ImportSelector 实现类。一般用于加载配置文件中的类
  4. 导入 ImportBeanDefinitionRegistrar 实现类

2. 使用

2.1 导入普通Bean

会自动执行当前类的构造方法创建对象,存到IOC容器, bean名称为:类的全路径

构造一个类

public class User {

    private Integer id;

    private String name;
	
	//	get set 略
	
    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

使用第一种方式导入

package com.snow;

import com.snow.po.User;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Import;

@Import(User.class)//会自动执行当前类的构造方法创建对象,存到IOC容器, bean名称为:类的全路径
@SpringBootApplication
public class TempApplication {

    public static void main(String[] args) {

        ConfigurableApplicationContext applicationContext = SpringApplication.run(TempApplication.class, args);

        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();

        // 获取并使用每个bean
        for (String beanName : beanDefinitionNames) {
            Object bean = applicationContext.getBean(beanName);
            System.out.println("Bean: " + beanName + " - " + bean.getClass().getName());
            // 在这里可以进行进一步的操作
        }

        // 关闭应用程序上下文
        applicationContext.close();
    }
}

执行结果如下:
在这里插入图片描述

可以看到 User 类被注入了容器.


2.2 导入配置类

创建 MyConfig bean,并且类中有 带有@Bean注解方法,创建对象存到IOC容器,bean名称为:默认方法名称

定义一个类

public class Student {

    private Integer id;

    private String name;

    
    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }

}

创建配置类

@Configuration
public class MyConfig {

    @Bean
    public Student student() {
        return new Student();
    }
    
}

第二种方式注入

//@Import(User.class)//会自动执行当前类的构造方法创建对象,存到IOC容器, bean名称为:类的全路径
@Import(MyConfig.class) //  创建MyConfig bean,并且类中有 带有@Bean注解方法,创建对象存到IOC容器,bean名称为:默认方法名称
@SpringBootApplication
public class TempApplication {

    public static void main(String[] args) {

        ConfigurableApplicationContext applicationContext = SpringApplication.run(TempApplication.class, args);

        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();

        // 获取并使用每个bean
        for (String beanName : beanDefinitionNames) {
            Object bean = applicationContext.getBean(beanName);
            System.out.println("Bean: " + beanName + " - " + bean.getClass().getName());
            // 在这里可以进行进一步的操作
        }

        // 关闭应用程序上下文
        applicationContext.close();
    }
}

执行并查看结果:
在这里插入图片描述
可以看到注入进来了配置类本身及其配置类里面声明的bean.


2.3 导入 ImportSelector 实现类

@ImportSelector 是 Spring 框架提供的一个接口,用于动态地选择需要导入的配置类。通过实现该接口,可以根据特定的条件在运行时选择性地导入一组配置类,从而实现更加灵活的配置管理。

具体来说,@ImportSelector 接口定义了一个方法 selectImports(),该方法返回一个字符串数组,数组中包含需要导入的配置类的全限定类名。当在 Spring 配置类中使用 @Import 注解并指定实现了 @ImportSelector 接口的类时,Spring 在加载配置类时会调用该类的 selectImports() 方法,根据方法返回的配置类的全限定类名来加载相应的配置类。

使用 @ImportSelector 的主要优势在于可以根据程序运行时的条件来动态地选择性地导入配置类,从而实现更加灵活的组件管理和配置。例如,可以根据环境变量、配置文件的内容或者其他动态条件来决定需要加载哪些配置类,从而实现不同环境下的定制化配置。

定义一个类

public class Teacher {

    private Integer id;

    private String name;

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

编写 ImportSelector 的实现类: MyImportSelector如下:

public class MyImportSelector implements ImportSelector {

    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
    	//	返回类的全路径的字符串数组
        return new String[]{"com.snow.po.Teacher"};
    }
}

第三张方式注入

//@Import(User.class)//会自动执行当前类的构造方法创建对象,存到IOC容器, bean名称为:类的全路径
//@Import(MyConfig.class) //  创建MyConfig bean,并且类中有 带有@Bean注解方法,创建对象存到IOC容器,bean名称为:默认方法名称
@Import(MyImportSelector.class) // 会调用 MyImportSelector 类的 selectImports() 方法,该方法返回一个类名称的数组,Spring 将加载这些类,这样它们的配置信息就可以被应用到当前的上下文中。
@SpringBootApplication
public class TempApplication {

    public static void main(String[] args) {

        ConfigurableApplicationContext applicationContext = SpringApplication.run(TempApplication.class, args);

        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();

        // 获取并使用每个bean
        for (String beanName : beanDefinitionNames) {
            Object bean = applicationContext.getBean(beanName);
            System.out.println("Bean: " + beanName + " - " + bean.getClass().getName());
            // 在这里可以进行进一步的操作
        }

        // 关闭应用程序上下文
        applicationContext.close();
    }
}

执行并看结果:
在这里插入图片描述

注意: 这种方式是最重要的, SpringBoot自动装配核心使用了这种方式自动注入大量Bean.


2.4 导入 ImportBeanDefinitionRegistrar 实现类

导入 ImportBeanDefinitionRegistrar 实现类的作用是允许在 Spring 应用程序上下文加载时以编程方式注册额外的 bean 定义。与 ImportSelector 类似,ImportBeanDefinitionRegistrar 接口也提供了一种动态注册 bean 定义的机制,但是它更加灵活,可以在注册过程中对 bean 定义进行更复杂的操作。

当你使用 @Import 注解导入实现了 ImportBeanDefinitionRegistrar 接口的类时,Spring 在加载配置类时会调用该类的 registerBeanDefinitions() 方法。在这个方法中,你可以通过编程方式注册 bean 定义,包括指定 bean 的名称、类型、作用域以及其他属性。

通过使用 ImportBeanDefinitionRegistrar,你可以在运行时根据需要动态地注册 bean,这样可以更灵活地管理和配置 Spring 应用程序的组件。这种机制特别适用于需要根据外部条件或者动态变化的情况下注册 bean 的场景,例如基于配置文件或者运行时环境来决定需要注册哪些 bean。

定义一个类

public class School {

    private Integer id;

    private String name;
    
    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }

}

实现ImportBeanDefinitionRegistrar 接口

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

    /**
     * @param importingClassMetadata 导入类的元注解信息
     * @param registry Bean注册表
     */
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder
                .rootBeanDefinition(School.class).getBeanDefinition();
        registry.registerBeanDefinition("school", beanDefinition);
    }

}

第四种方式导入

@Import(MyImportBeanDefinitionRegistrar.class)
@SpringBootApplication
public class TempApplication {

    public static void main(String[] args) {

        ConfigurableApplicationContext applicationContext = SpringApplication.run(TempApplication.class, args);

        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();

        // 获取并使用每个bean
        for (String beanName : beanDefinitionNames) {
            Object bean = applicationContext.getBean(beanName);
            System.out.println("Bean: " + beanName + " - " + bean.getClass().getName());
            // 在这里可以进行进一步的操作
        }

        // 关闭应用程序上下文
        applicationContext.close();
    }
}

执行看结果
在这里插入图片描述

可以看到注册成功.


3. 区别

@Import(MyImportSelector.class) 和 @Import(MyImportBeanDefinitionRegistrar.class) 都是用于在 Spring 中动态导入配置信息的注解,但它们的作用和使用场景略有不同。

  1. @Import(MyImportSelector.class):

    • 作用:通过实现 ImportSelector 接口的类,动态地选择需要导入的配置类。
    • 使用场景:通常用于根据某些条件动态地选择需要导入的配置类。例如,根据环境变量或者配置文件中的设置来决定需要加载哪些组件或配置。
  2. @Import(MyImportBeanDefinitionRegistrar.class):

    • 作用:通过实现 ImportBeanDefinitionRegistrar 接口的类,以编程方式注册额外的 bean 定义。
    • 使用场景:通常用于需要根据运行时动态条件注册 bean 的场景。例如,根据系统配置或者运行时环境来决定需要注册哪些 bean,或者根据一些复杂的逻辑来注册 bean。

使用场景示例:

如果需要根据一些条件在运行时动态地选择性地加载一些配置类,可以使用@Import(MyImportSelector.class)。

如果需要在运行时根据条件注册一些 bean,可能需要进行一些复杂的逻辑判断,并且注册的 bean 可能不只是简单地选择性加载配置类,你可以使用 @Import(MyImportBeanDefinitionRegistrar.class)。





在这里插入图片描述



本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/531564.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

即插即用篇 | YOLOv5/v7引入Haar小波下采样 | 一种简单而有效的语义分割下采样模块

本改进已集成到 YOLOv5-Magic 框架。 下采样操作如最大池化或步幅卷积在卷积神经网络(CNNs)中被广泛应用,用于聚合局部特征、扩大感受野并减少计算负担。然而,对于语义分割任务,对局部邻域的特征进行池化可能导致重要的空间信息丢失,这有助于逐像素预测。为了解决这个问题…

动态规划刷题(2)之杨辉三角(详细解释)

最近在自学动态规划,网上到处找资料学习: 在这里记录我的刷题历史: 题目都是在力扣里面刷的!! 这里,我放一个刷动态规划的链接在这里:动态规划知识点题库 - 力扣(LeetCode) 力扣 在这里附加动态规划相关知识点:动态规划(DP)-CSDN博客文章浏览阅读197次。动态规划…

简单的配置信息保存一例

上位机程序通常都会需要保存一些用户的配置信息。比如名称,年龄等 设置文件的使用非常方便,在项目名称上右击,选择“添加/新建项”。 如下图: 新建项目 新插入的设置文件Settings1会自动打开。添加对应项目 数据类型分别为str…

2024年第五届计算机视觉与信息技术国际会议(CVIT 2024)即将召开!

2024年第五届计算机视觉与信息技术国际会议(CVIT 2024)将于2024年8月16-18日在北京举行。CVIT 2024由北方工业大学主办,国内外的专家学者将齐聚一堂,共同分享最新的技术突破、研究方法和应用案例,共同推动计算机视觉与…

自动驾驶定位算法-递归贝叶斯滤波(Bayes Filter)

自动驾驶定位算法-递归贝叶斯滤波(Bayes Filter) 附赠自动驾驶学习资料和量产经验:链接 贝叶斯滤波器(Bayes Filter)是无人驾驶汽车中高精定位相关的基础技术,同时也是机器人技术中的基础算法。 如上图,开始机器人不知道自己在哪里&#xff…

gurobi不同版本切换

每年年底,gurobi都会推出新版本。新版本是大的迭代更新,求解问题的效率和精度都会提升。官方人员一般会建议我们安装最新的版本,此外,写论文审稿专家也会建议我们使用较新的版本。 从我们现装的版本切换到新版本。我以往的做法是…

微信朋友圈定时神器必须拥有!随时随地轻松发圈!

在微信朋友圈这个社交平台上,很多人都希望通过发布内容来进行个人推广或商业营销。但是,在忙碌或是节假日时,想要随意发布内容也会有些麻烦。 今天我要向大家分享的是一个微信朋友圈定时发布的神器,让您随时随地轻松发圈&#xf…

分享 GoLand 2024.1 激活的方案,支持JetBrains全家桶

大家好,欢迎来到金榜探云手! GoLand 公司简介 JetBrains 是一家专注于开发工具的软件公司,总部位于捷克。他们以提供强大的集成开发环境(IDE)而闻名,如 IntelliJ IDEA、PyCharm、和 GoLand等。这些工具被广…

旧衣回收市场发展快速,线上小程序为商家提供新机遇

随着人们生活水平的提高,衣服淘汰的速度也在不断加快,每年垃圾站都会有非常多的废弃衣物。旧衣物的废弃不仅对环境有破坏,还造成了资源浪费。 因此,旧衣物回收行业受到了大众的关注,旧衣回收市场具有先天的优势&#…

十六进制前缀为Ox还是0x???

16进制的前缀是0x,数字零和英文字母X。 十六进制(英文名称:Hexadecimal),是计算机中数据的一种表示方法。同我们日常生活中的表示法不一样。它由0-9,A-F组成,字母不区分大小写。与10进制的对应…

基于 SSM 医院病历管理系统的设计与实现

摘 要 病历管理系统是医院管理系统的重要组成,在计算机技术快速发展之前,病人或者医生如果想记录并查看自己的健康信息是非常麻烦的,因为在以往病人的健康信息通常只保存在自己的病历卡或者就诊报告中,如果在就诊时想进行查看只能通过观看…

突如其来:OpenAI分家的Anthropic公司悄悄地释放出他们的秘密武器——Claude3

突如其来的消息,OpenAI分家的Anthropic公司悄悄地释放出他们的秘密武器——Claude3 这货居然在默默无闻中一举超越了GPT-4的地位。没发布会,没吹牛逼,就发了一帖子。 字少,事大。 Claude3独挡一面的推理能力 Anthropic推出了三款…

数学建模笔记(10)整数规划和0-1规划

前由 显然通关次数不能是小数,这就涉及到了整数问题。 定义 例题

骨传导耳机哪个牌子好?热销榜TOP5机型大揭秘!

市场上的骨传导耳机品质参差不齐,大家在挑选产品时一定要注意,避免入手到劣质产品,要知道,这些劣质产品不仅仅是使用体验差,并且长时间使用还容易损伤身体健康,那么面对市面上如此多的骨传导耳机品牌&#…

蓝桥杯嵌入式2023年第十四届省赛主观题解析

1 题目 2 代码 /* Includes ------------------------------------------------------------------*/ #include "main.h" #include "adc.h" #include "rtc.h" #include "tim.h" #include "gpio.h"/* Private includes --…

可在手机上运行的2B LLMs ,看看斯坦福大学的这个项目

项目简介 Octopus-V2-2B是由斯坦福大学Nexa AI开发的一种先进的开源大型语言模型,具有20亿参数,专为Android API的功能调用定制。 与需要详细描述潜在函数参数的检索增强生成(RAG)方法不同Octopus-V2-2B采用了一种独特的功能性标记(functionaltokens)策…

离散化实现低通滤波器(选用双线性变换)

学习了离散化后整理了其中的核心步骤,此处不对原理进行深究,仅仅介绍如何对一个连续系统进行离散化 此处可以得到低通滤波器的截止频率为1000rad/s. 离散化的过程为将s 2/Ts * [(z - 1) / (z 1)] (选用双线性变换) 得到离散化序列为 Y(z) [w…

02.安装MySQL

安装MySQL 1.Windows使用压缩包安装MySQL8 下载安装包 地址:https://downloads.mysql.com/archives/community/ 解压安装包在没有中文和空格的目录下 省略 在解压目录创建my.ini文件并添加内容如下 不创建也是可以的,让它用默认的 配置环境变量 省…

Kubernetes学习笔记13

K8s集群核心概念:Service 我们在之前的学习过程中遇到一个问题,就是如果Pod被误删除,那么Controller重新拉起一个新的Pod时,我们发现PodIP地址是变化着的,我们访问必须更新IP地址。 这样对于大量的Pod运行应用来说&a…

Linux双网卡默认路由优先级设置不正确,导致网络不通问题定位

问题描述 RHEL9 双网卡环境,两个网卡配置如下:(eth0 走内网,eth1 走外网) eth0 192.168.10.20/24 网关: 192.168.10.254 eth1 10.206.216.92/24 网关: 10.206.216.254配置完成后,curl https://www.baidu.com访问百度失…