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

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: SpringBoot自动装配原理之@Import注解解析

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 中动态导入配置信息的注解,但它们的作用和使用场景略有不同。


@Import(MyImportSelector.class):


作用:通过实现 ImportSelector 接口的类,动态地选择需要导入的配置类。

使用场景:通常用于根据某些条件动态地选择需要导入的配置类。例如,根据环境变量或者配置文件中的设置来决定需要加载哪些组件或配置。

@Import(MyImportBeanDefinitionRegistrar.class):


作用:通过实现 ImportBeanDefinitionRegistrar 接口的类,以编程方式注册额外的 bean 定义。

使用场景:通常用于需要根据运行时动态条件注册 bean 的场景。例如,根据系统配置或者运行时环境来决定需要注册哪些 bean,或者根据一些复杂的逻辑来注册 bean。

使用场景示例:


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


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


目录
打赏
0
0
0
0
59
分享
相关文章
解析:HTTPS通过SSL/TLS证书加密的原理与逻辑
HTTPS通过SSL/TLS证书加密,结合对称与非对称加密及数字证书验证实现安全通信。首先,服务器发送含公钥的数字证书,客户端验证其合法性后生成随机数并用公钥加密发送给服务器,双方据此生成相同的对称密钥。后续通信使用对称加密确保高效性和安全性。同时,数字证书验证服务器身份,防止中间人攻击;哈希算法和数字签名确保数据完整性,防止篡改。整个流程保障了身份认证、数据加密和完整性保护。
深入解析图神经网络注意力机制:数学原理与可视化实现
本文深入解析了图神经网络(GNNs)中自注意力机制的内部运作原理,通过可视化和数学推导揭示其工作机制。文章采用“位置-转移图”概念框架,并使用NumPy实现代码示例,逐步拆解自注意力层的计算过程。文中详细展示了从节点特征矩阵、邻接矩阵到生成注意力权重的具体步骤,并通过四个类(GAL1至GAL4)模拟了整个计算流程。最终,结合实际PyTorch Geometric库中的代码,对比分析了核心逻辑,为理解GNN自注意力机制提供了清晰的学习路径。
160 7
深入解析图神经网络注意力机制:数学原理与可视化实现
深入解析Tiktokenizer:大语言模型中核心分词技术的原理与架构
Tiktokenizer 是一款现代分词工具,旨在高效、智能地将文本转换为机器可处理的离散单元(token)。它不仅超越了传统的空格分割和正则表达式匹配方法,还结合了上下文感知能力,适应复杂语言结构。Tiktokenizer 的核心特性包括自适应 token 分割、高效编码能力和出色的可扩展性,使其适用于从聊天机器人到大规模文本分析等多种应用场景。通过模块化设计,Tiktokenizer 确保了代码的可重用性和维护性,并在分词精度、处理效率和灵活性方面表现出色。此外,它支持多语言处理、表情符号识别和领域特定文本处理,能够应对各种复杂的文本输入需求。
50 6
深入解析Tiktokenizer:大语言模型中核心分词技术的原理与架构
分片上传技术全解析:原理、优势与应用(含简单实现源码)
分片上传通过将大文件分割成多个小的片段或块,然后并行或顺序地上传这些片段,从而提高上传效率和可靠性,特别适用于大文件的上传场景,尤其是在网络环境不佳时,分片上传能有效提高上传体验。 博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
深入理解HTTP/2:nghttp2库源码解析及客户端实现示例
通过解析nghttp2库的源码和实现一个简单的HTTP/2客户端示例,本文详细介绍了HTTP/2的关键特性和nghttp2的核心实现。了解这些内容可以帮助开发者更好地理解HTTP/2协议,提高Web应用的性能和用户体验。对于实际开发中的应用,可以根据需要进一步优化和扩展代码,以满足具体需求。
43 29
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
149 2
JS数组操作方法全景图,全网最全构建完整知识网络!js数组操作方法全集(实现筛选转换、随机排序洗牌算法、复杂数据处理统计等情景详解,附大量源码和易错点解析)
这些方法提供了对数组的全面操作,包括搜索、遍历、转换和聚合等。通过分为原地操作方法、非原地操作方法和其他方法便于您理解和记忆,并熟悉他们各自的使用方法与使用范围。详细的案例与进阶使用,方便您理解数组操作的底层原理。链式调用的几个案例,让您玩转数组操作。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
从入门到精通:H5游戏源码开发技术全解析与未来趋势洞察
H5游戏凭借其跨平台、易传播和开发成本低的优势,近年来发展迅猛。接下来,让我们深入了解 H5 游戏源码开发的技术教程以及未来的发展趋势。
在线教育网课系统源码开发指南:功能设计与技术实现深度解析
在线教育网课系统是近年来发展迅猛的教育形式的核心载体,具备用户管理、课程管理、教学互动、学习评估等功能。本文从功能和技术两方面解析其源码开发,涵盖前端(HTML5、CSS3、JavaScript等)、后端(Java、Python等)、流媒体及云计算技术,并强调安全性、稳定性和用户体验的重要性。

推荐镜像

更多