【@Import注解的使用】

@Import注解在Spring Boot中广泛使用,主要通过三种方式引入类到Spring容器:1) 导入普通类,直接创建实例;2) 导入配置类,创建配置类及其@Bean声明的bean;3) 导入ImportSelector和ImportBeanDefinitionRegistrar实现类,实现更灵活的bean注入。ImportSelector可以根据条件决定导入哪些类,而ImportBeanDefinitionRegistrar则能自定义bean定义并注册,具有更高的bean定义优先级。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • 在springboot的源码中大量使用到了@Import注解,所以我们有必要了解一下该注解的作用.
  • 使用位置:@Import只能用在类上
  • 属性: Class<?>[] value(); 类的字节码数组
  • 作用:@Import通过快速导入的方式实现把实例加入spring的IOC容器中

一 @Import引入一个普通类

  • 需要创建对象的类:Student类
    在这里插入图片描述
  • Config1类,通过Import导入Student.class ,Student是一个普通类
@Configuration
@Import({Student.class})
public class Config1 {

}

public class App1 {
    public static void main(String[] args) {
        //通过传入一个配置类Config1.class相当于配置文件,来得到对应容器对象AnnotationConfigApplicationContext
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(Config1.class);
        for (String beanDefinitionName : ac.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
    }
}

观察: 被注入对象的bean的名字是类的全路径类名,且首字母大写
在这里插入图片描述

  • 结论: 使用@Import导入普通类的话,会将该类的实例放到Spring容器中

@Import引入一个配置类,同时创建配置类中声明的bean对象

  • 所谓的配置类就是加了@Configuration注解的类,该类里面有用于创建其他的bean
  • 创建要导入的配置类:
@Configuration
public class MyConfig {
    @Bean
    public Dog dog(){ //里面使用@Bean注入一个dog对象到容器中
        return new Dog();
    }
}
  • 使用@Import导入
@Configuration
@Import({Student.class,MyConfig.class})
public class Config1 {

}
  • 输出容器对象中所有的bean
public class App1 {
    public static void main(String[] args) {
        //通过传入一个配置类Config1.class相当于配置文件,来得到对应容器对象AnnotationConfigApplicationContext
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(Config1.class);
        for (String beanDefinitionName : ac.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
    }
}

在这里插入图片描述

  • 结论: 使用@Import注解导入配置类的话,不光会创建配置类的对象,同时在配置类中所有需要创建的对象(例如使用@Bean注解)也会被加载到spring容器中

二 @Import引入ImportSelector的实现类(重点)

  • springboot的自动装配中大量使用到导入ImportSelector的实现类
  • ImportSelector接口:
public interface ImportSelector {
	//selectorImports方法是重点
    String[] selectImports(AnnotationMetadata importingClassMetadata);

    @Nullable
    default Predicate<String> getExclusionFilter() {
        return null;
    }
}

解释:
        String[] selectImports(AnnotationMetadata importingClassMetadata);

  1. 返回值: 一个String的字符串数组
  2. 参数:AnnotationMetadata类型 ,可以获取导入了ImportSelector实现类并加了@Import注解所在的类,的一些信息
  • 创建一个ImportSelector的实现类,并重写selectImports方法
public class MyImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        String[] strings = {"com.example.pojo.Dog"}; //返回的字符串是Dog类的全路径类名
        return strings;
    }
}
  • 导入这个实现类
@Configuration
@Import({MyImportSelector.class}) //导入ImportSelector的实现类
public class Config1 {

}
  • 运行程序
public class App1 {
    public static void main(String[] args) {
        //得到容器对象AnnotationConfigApplicationContext
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(Config1.class);
        for (String beanDefinitionName : ac.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
    }
}




发现创建了selectImports方法返回字符串全限定类名对应的实例到容器中

在这里插入图片描述

  • 所以我们折腾一圈还是为了创建某个类的实例到容器中,那为什么要使用这种方式呢?又比较麻烦
  • 这种方法最终的效果: 将ImportSelector的实现类中的selectImports方法的返回值对应类的全限定类名字符串的实例注入到容器中.
  • 和之前注入bean实例的区别,selectImports方法中的参数AnnotationMetadata importingClassMetadata,注解元数据,该参数可以拿到很多信息,来帮助我们决定最后返回的字符串中究竟要创建哪些实例.

该参数可以使用的一些方法:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 既然这个参数可以获取这么多信息,但是究竟它获取到的是哪个类上的信息呢?
    在这里插入图片描述
    在这里插入图片描述
  • 这样就可以实现更加灵活的注入实例到容器中,可以加一些自己的逻辑条件,满足某些要求时,我就返回某些类的全限定类名,里面的逻辑可以自己控制.
  • 比如:如果@Import注解所在类上加了@Configuration注解我就创建Student对象,否则我就创建Dog对象
@Configuration
@Import({MyImportSelector.class})
public class Config1 {

}
public class MyImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        System.out.println("---------------");
        System.out.println(importingClassMetadata.hasAnnotation("org.springframework.context.annotation.Configuration"));
        if(importingClassMetadata.hasAnnotation("org.springframework.context.annotation.Configuration")){
            return new String[]{"com.example.pojo.Student"};
        }else{
            return new String[]{"com.example.pojo.Dog"};
        }


    }
}

在这里插入图片描述
在这里插入图片描述

  • 如果我将@Configuration注解去掉
    在这里插入图片描述
  • 当然AnnotationMetadata可以获取的信息还有很多,不仅是可以判断是否加了某些注解,还能获取到注解中的属性值,这些都可以作为我们判断的条件,根据判断来决定我们最终需要注入的实例究竟是哪些.

三 @Import引入ImportBeanDefinitionRegistrar的实现类(重点)

  • 在 ImportBeanDefinitionRegistrar接口中有一个方法registerBeanDefinitions方法,里面可以定义bean到容器中
public interface ImportBeanDefinitionRegistrar {
    default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {
        this.registerBeanDefinitions(importingClassMetadata, registry);
    }
	//我们重点使用这个方法,上面的和这个是差不多的,只是参数多一个
    default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    }
}
  • 在这里面创建的bean的优先级比使用注解@Service,@Component这几个注解创建的bean的优先级更高,也就是这里面创建的bean如果同名的话能够覆盖前面创建的
  • 编写一个实现类:
public class MyBeanDefinition implements ImportBeanDefinitionRegistrar{
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
       //importingClassMetadata是元注解,也是可以获取到Import使用所在类上的所有注解信息,也可以作为判断条件

//获取BeanDefinition对象的方式不唯一,有很多
        BeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Student.class).getBeanDefinition();
        //注册bean,在这里面注册bean的自由度更大,bean的名字还有其他属性都可以自定义
        registry.registerBeanDefinition("myStudent",beanDefinition);
    }
}
  • 将该实现类导入
@Configuration
@Import({MyBeanDefinition.class})
public class Config1 {

}

  • 运行程序
    在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值