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

简介: 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)。


相关文章
|
22小时前
|
Java 应用服务中间件 Spring
解析Spring Boot自动装配的原理与机制
解析Spring Boot自动装配的原理与机制
13 4
|
1天前
|
XML Java 数据格式
Spring框架第三章(基于注解管理bean)
Spring框架第三章(基于注解管理bean)
|
1天前
|
Java 开发者 Spring
深入解析这两种扩展机制的工作原理和用法
深入解析这两种扩展机制的工作原理和用法
|
2天前
|
缓存 NoSQL Java
在 SSM 架构(Spring + SpringMVC + MyBatis)中,可以通过 Spring 的注解式缓存来实现 Redis 缓存功能
【6月更文挑战第18天】在SSM(Spring+SpringMVC+MyBatis)中集成Redis缓存,涉及以下步骤:添加Spring Boot的`spring-boot-starter-data-redis`依赖;配置Redis连接池(如JedisPoolConfig)和连接工厂;在Service层使用`@Cacheable`注解标记缓存方法,指定缓存名和键生成策略;最后,在主配置类启用缓存注解。通过这些步骤,可以利用Spring的注解实现Redis缓存。
17 2
|
2天前
|
XML Java 数据格式
Spring Boot自动配置是通过`@EnableAutoConfiguration`注解启用的
【6月更文挑战第18天】Spring Boot的`@EnableAutoConfiguration`启动自动配置,基于类路径扫描和条件注解(如@ConditionalOnClass)选择性应用配置。当检测到特定依赖时,自动配置模块会将对应的bean添加到应用上下文,简化了XML或Java配置。只需添加依赖,即可自动配置功能。
11 4
|
2天前
|
存储 缓存 Java
滚雪球学Java(64):LinkedHashSet原理及实现解析
【6月更文挑战第18天】🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
11 1
滚雪球学Java(64):LinkedHashSet原理及实现解析
|
XML Java 数据格式
SpringBoot原理分析
SpringBoot原理分析
SpringBoot原理分析
|
Java Maven 容器
SpringBoot 核心原理分析
SpringBoot 核心原理分析
166 0
SpringBoot 核心原理分析
|
1天前
|
JavaScript Java 测试技术
基于SpringBoot+Vue的太原学院在线考试系统的详细设计和实现(源码+lw+部署文档+讲解等)
基于SpringBoot+Vue的太原学院在线考试系统的详细设计和实现(源码+lw+部署文档+讲解等)
24 12
|
1天前
|
JavaScript Java 测试技术
基于SpringBoot+Vue的学生管理系统的详细设计和实现(源码+lw+部署文档+讲解等)
基于SpringBoot+Vue的学生管理系统的详细设计和实现(源码+lw+部署文档+讲解等)
24 12

推荐镜像

更多