Spring Boot 2.x实战9 - Spring 5.x基础7 - 理解 @Enable*和@Import

2.9 开启配置 - @Enable*和@Import

在后面的内容里会出现大量以@Enable*开头的注解,通过@Enable*将会自动对相应的功能进行自动配置。如:@EnableWebMvc@EnableCaching@EnableScheduling@EnableAsync@EnableWebSocketEnableJpaRepositories@EnableTransactionManagement@EnableJpaAuditing@EnableAspectJAutoProxy等。

而这开启配置的功能时由@Import注解提供的,@Import注解支持导入如下的配置:

  • 直接导入@Configuration配置类;
  • 配置类选择器ImportSelector的实现;
  • 动态注册器ImportBeanDefinitionRegistrar的实现。
  • 混合以上三种

下面我们将分别演示三种方式的实现:

2.9.1 直接导入@Configuration配置类

应用了注解了@Configuration都会被Spring Boot的默认组件扫描自动注册,所以我们将本节的注解类代码放入io.github.wiselyman.annotations包中,配置类的代码放入io.github.wiselyman.config中:

定义注解:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AConfig.class) //直接导入配置类AConfig.class
public @interface EnableA {
}

定义配置类:

@Configuration
public class AConfig {

    @Bean
    public String a(){
        return "A";
    }
}

JavaConfig中使用@EnableA注解,即可获得导入的配置类AConfig中的Bean a

@EnableA
public class JavaConfig {}

JavaConfig中使用CommandLineRunner执行:

@Bean
CommandLineRunner enableAClr(String a){
    return args -> System.out.println(a);
}

在这里插入图片描述

2.9.2 配置类选择器ImportSelector的实现

在这个例子里,我们通过注解选择起效的配置类,注解定义如下:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(BSelector.class) 
public @interface EnableB {

    boolean isUppercase() default true; //isUppercase是用来作为选择条件的
}

io.github.wiselyman.selector里定义选择器:

public class BSelector implements ImportSelector { //1
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) { //2 
        AnnotationAttributes attributes =
                AnnotationAttributes.fromMap(
                        importingClassMetadata.getAnnotationAttributes
                                (EnableB.class.getName(), false)); 
        boolean isUppercase = attributes.getBoolean("isUppercase"); //3
        if(isUppercase == true) 
            return new String[]{"io.github.wiselyman.config.BUppercaseConfig"}; //4
        else
            return new String[]{"io.github.wiselyman.config.BLowercaseConfig"}; //5
    }
}
  1. 选择器要实现ImportSelector接口;
  2. 实现接口的selectImports方法,参数AnnotationMetadata importClassMetadata是注解使用类(本例为JavaConfig)上@EnableB的元数据信息;
  3. 通过@EnableB在实际使用中的元数据,获得isUppercase的值;
  4. 如果isUppercase == true,此时实际使用时是@EnableB或者@EnableB(isUppercase = true)使用BUppercaseConfig提供的配置;
  5. 若实际使用时@EnableB(isUppercase = false)否则使用BLowercaseConfig提供的配置。

BUppercaseConfig的定义:

@Configuration
public class BUppercaseConfig {
    @Bean
    public String b(){
        return "B"; //返回一个大写B的Bean的配置
    }
}

BLowercaseConfig的定义:

@Configuration
public class BLowercaseConfig {
    @Bean
    public String b(){
        return "b"; //返回一个小写b的Bean的配置
    }
}

JavaConfig中使用@EnableB,并用CommandLineRunner检验:

@EnableB
public class JavaConfig {}
@Bean
CommandLineRunner enbaleBClr(String b){
    return args -> System.out.println(b);
}

在这里插入图片描述
若将isUppercase设置为false,如:

@EnableB(isUppercase = false)
public class JavaConfig {}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wGiP8zc2-1587716328499)(images/running-enable-3.png)]

2.9.3 动态注册器ImportBeanDefinitionRegistrar的实现

本例通过ImportBeanDefinitionRegistrar可动态注册Bean到容器里。

注解定义:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(CBeanDefinitionRegistrar.class)
public @interface EnableC {
}

io.github.wiselyman.registrar包中定义注册器:

public class CBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { //1
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, //2
                                        BeanDefinitionRegistry registry) { //3
        BeanDefinition bd = BeanDefinitionBuilder.genericBeanDefinition(String.class) //4
                                            .addConstructorArgValue("C") //5
                                            .setScope(BeanDefinition.SCOPE_SINGLETON) //6
                                            .getBeanDefinition(); //7
       registry.registerBeanDefinition("c",bd); //8
    }
}
  1. 注册器需实现ImportBeanDefinitionRegistrar接口;
  2. 实现registerBeanDefinitions,参数AnnotationMetadata importClassMetadata是注解使用类(本例为JavaConfig)上@EnableB的元数据信息;
  3. 参数BeanDefinitionRegistry registry是用来注册所有Bean的定义的接口;
  4. 我们可以使用BeanDefinitionBuilder来编程式实现Bean的定义(BeanDefinition),此句定义了一个类型为String的Bean;
  5. 构造String的值是C;
  6. 设置Bean的Scope是singleton;
  7. 获得Bean的定义;
  8. 将Bean注册为名称为c的Bean。

此时我们在JavaConfig上使用@EnableC,并用CommandLineRunner检验:

@EnableC
public class JavaConfig {}
@Bean
CommandLineRunner enableCClr(String c){
    return args -> System.out.println(c);
}

静态注册的Bean,IntelliJ IDEA可以检测到,而动态注册的检测不到,所以这时候IDE会标红,但是正常运行:

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

2.9.4 混合使用

@Import支持导入配置类的数组,我们可以混合上面三种配置,如我们可以定义一个注解具备上面三个的功能:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({AConfig.class, BForABCSelector.class, CBeanDefinitionRegistrar.class})
public @interface EnableABC {
    boolean isUppercase() default true;
}

选择器里指定了使用的注解的类,所以要新建一个新选择器:

public class BForABCSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        AnnotationAttributes attributes =
                AnnotationAttributes.fromMap(
                        importingClassMetadata.getAnnotationAttributes
                                (EnableABC.class.getName(), false)); // 此处使用的是@EnableABC
        boolean isUppercase = attributes.getBoolean("isUppercase");
        if(isUppercase == true)
            return new String[]{"io.github.wiselyman.config.BUppercaseConfig"};
        else
            return new String[]{"io.github.wiselyman.config.BLowercaseConfig"};
    }
}

我们在JavaConfig中启用@EnableABC并用CommandLineRunner检验:

@EnableABC
public class JavaConfig {}
@Bean
CommandLineRunner enableABCClr(String a, String b, String c){
    return args -> {
        System.out.println(a);
        System.out.println(b);
        System.out.println(c);
    };
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gzf4iWgF-1587716428609)(images/running-enable-6.png)]

新书推荐:

我的新书《从企业级开发到云原生微服务:Spring Boot 实战》已出版,内容涵盖了丰富Spring Boot开发的相关知识
购买地址:https://item.jd.com/12760084.html

在这里插入图片描述

主要包含目录有:

第一章 初识Spring Boot(快速领略Spring Boot的美丽)
第二章 开发必备工具(对常用开发工具进行介绍:包含IntelliJ IDEA、Gradle、Lombok、Docker等)
第三章 函数式编程
第四章 Spring 5.x基础(以Spring 5.2.x为基础)
第五章 深入Spring Boot(以Spring Boot 2.2.x为基础)
第六章 Spring Web MVC
第七章 数据访问(包含Spring Data JPA、Spring Data Elasticsearch和数据缓存)
第八章 安全控制(包含Spring Security和OAuth2)
第九章 响应式编程(包含Project Reactor、Spring WebFlux、Reactive NoSQL、R2DBC、Reactive Spring Security)
第十章 事件驱动(包含JMS、RabbitMQ、Kafka、Websocket、RSocket)
第11章 系统集成和屁股里(包含Spring Integration和Spring Batch)
第12章 Spring Cloud与微服务
第13章 Kubernetes与微服务(包含Kubernetes、Helm、Jenkins、Istio)
多谢大家支持。

发布了116 篇原创文章 · 获赞 10 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/wiselyman/article/details/105733878