《深入浅出Spring》Spring注解@import

@Import出现的背景

目前为止,注解的方式批量注册bean,前面2篇文章中,我们介绍了2种方式:

到目前,我们知道的批量定义bean的方式有2种:

@Configuration结合@Bean注解的方式
@CompontentScan扫描包的方式
下面我们来看几个问题。

问题1

如果需要注册的类是在第三方的jar中,那么我们如果想注册这些bean有2种方式:

通过@Bean标注方法的方式,一个个来注册
@CompontentScan的方式:默认的@CompontentScan是无能为力的,默认情况下只会注册@Compontent标注的类,此时只能自定义@CompontentScan中的过滤器来实现了
这2种方式都不是太好,每次有变化,调整的代码都比较多。

问题2

通常我们的项目中有很多子模块,可能每个模块都是独立开发的,最后通过jar的方式引进来,每个模块中都有各自的@Configuration、@Bean标注的类,或者使用@CompontentScan标注的类,被@Configuration、@Bean、@CompontentScan标注的类,我们统称为bean配置类,配置类可以用来注册bean,此时如果我们只想使用其中几个模块的配置类,怎么办?

@Import可以很好的解决这2个问题,下面我们来看@Import怎么玩的。

@Import使用

先看Spring对它的注释,总结下来作用就是和xml配置的 标签作用一样,允许通过它引入@Configuration标注的类 , 引入ImportSelector接口和ImportBeanDefinitionRegistrar接口的实现,也包括 @Component注解的普通类。

总的来说:@Import可以用来批量导入需要注册的各种类,如普通的类、配置类,完后完成普通类和配置类中所有bean的注册。

@Import的源码:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {
   
    /**
     * {@link Configuration @Configuration}, {@link ImportSelector},
     * {@link ImportBeanDefinitionRegistrar}, or regular component classes to import.
     */
    Class<?>[] value();
}

@Import可以使用在任何类型上,通常情况下,类和注解上用的比较多。

value:一个Class数组,设置需要导入的类,可以是@Configuration标注的列,可以是ImportSelector接口或者ImportBeanDefinitionRegistrar接口类型的,或者需要导入的普通组件类。

使用步骤

  • 将@Import标注在类上,设置value参数
  • 将@Import标注的类作为AnnotationConfigApplicationContext构造参数创建AnnotationConfigApplicationContext对象
  • 使用AnnotationConfigApplicationContext对象

@Import的value常见的有5种用法

  • value为普通的类
  • value为@Configuration标注的类
  • value为@CompontentScan标注的类
  • value为ImportBeanDefinitionRegistrar接口类型
  • value为ImportSelector接口类型
  • value为DeferredImportSelector接口类型

value为普通的类

总配置类:使用@Import标注

import org.springframework.context.annotation.Import;
@Import({
   Service1.class, Service2.class})
public class MainConfig1 {
   
}

@Import中导入了2个普通的类:Service1、Service2,这两个类会被自动注册到容器中

我们也可以指定被导入类的bean名称,使用@Compontent注解就可以了,如下:

@Component("service1")
public class Service1 {
   
}

value为@Configuration标注的配置类

项目比较大的情况下,会按照模块独立开发,每个模块在maven中就表现为一个个的构建,然后通过坐标的方式进行引入需要的模块。

假如项目中有2个模块,2个模块都有各自的配置类,如下:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
 * 模块1配置类
 */
@Configuration
public class ConfigModule1 {
   
    @Bean
    public String module1() {
   
        return "我是模块1配置类!";
    }
}

模块2的配置类:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
 * 模块2配置类
 */
@Configuration
public class ConfigModule2 {
   
    @Bean
    public String module2() {
   
        return "我是模块2配置类!";
    }
}

总配置类:通过@Import导入2个模块的配置类

import org.springframework.context.annotation.Import;
/**
 * 通过Import来汇总多个@Configuration标注的配置类
 */
@Import({
   ConfigModule1.class, ConfigModule2.class}) //@1
public class MainConfig2 {
   
}

@1导入了2个模块中的模块配置类,可以按需导入。

value为@CompontentScan标注的类

项目中分多个模块,每个模块有各自独立的包,我们在每个模块所在的包中配置一个@CompontentScan类,然后通过@Import来导入需要启用的模块。

/**
 * 通过@Import导入多个@CompontentScan标注的配置类
 */
@Import({
   CompontentScanModule1.class, CompontentScanModule2.class}) //@1
public class MainConfig3 {
   
}

@1导入了2个模块中的组件扫描类,可以按需导入。

ImportBeanDefinitionRegistrar接口

这个接口提供了通过spring容器api的方式直接向容器中注册bean。

接口的完整名称:

org.springframework.context.annotation.ImportBeanDefinitionRegistrar

源码:

public interface ImportBeanDefinitionRegistrar {
   
    default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry,
            BeanNameGenerator importBeanNameGenerator) {
   
        registerBeanDefinitions(importingClassMetadata, registry);
    }
    default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
   
    }
}

2个方法中主要有3个参数
importingClassMetadata
AnnotationMetadata类型的,通过这个可以获取被@Import注解标注的类所有注解的信息。

registry
BeanDefinitionRegistry类型,是一个接口,内部提供了注册bean的各种方法。

importBeanNameGenerator
BeanNameGenerator类型,是一个接口,内部有一个方法,用来生成bean的名称。

关于BeanDefinitionRegistry和BeanNameGenerator接口在来细说一下。

BeanDefinitionRegistry接口:bean定义注册器

bean定义注册器,提供了bean注册的各种方法,来看一下源码:

public interface BeanDefinitionRegistry extends AliasRegistry {
   
    /**
     * 注册一个新的bean定义
     * beanName:bean的名称
     * beanDefinition:bean定义信息
     */
    void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws 
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值