2.9 开启配置 - @Enable*和@Import
在后面的内容里会出现大量以@Enable*
开头的注解,通过@Enable*
将会自动对相应的功能进行自动配置。如:@EnableWebMvc
、@EnableCaching
、@EnableScheduling
、@EnableAsync
、@EnableWebSocket
、EnableJpaRepositories
、@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
}
}
- 选择器要实现
ImportSelector
接口; - 实现接口的
selectImports
方法,参数AnnotationMetadata importClassMetadata
是注解使用类(本例为JavaConfig
)上@EnableB
的元数据信息; - 通过
@EnableB
在实际使用中的元数据,获得isUppercase
的值; - 如果
isUppercase == true
,此时实际使用时是@EnableB
或者@EnableB(isUppercase = true)
使用BUppercaseConfig
提供的配置; - 若实际使用时
@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 {}
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
}
}
- 注册器需实现
ImportBeanDefinitionRegistrar
接口; - 实现
registerBeanDefinitions
,参数AnnotationMetadata importClassMetadata
是注解使用类(本例为JavaConfig
)上@EnableB
的元数据信息; - 参数
BeanDefinitionRegistry registry
是用来注册所有Bean的定义的接口; - 我们可以使用
BeanDefinitionBuilder
来编程式实现Bean的定义(BeanDefinition
),此句定义了一个类型为String
的Bean; - 构造String的值是C;
- 设置Bean的Scope是singleton;
- 获得Bean的定义;
- 将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);
};
}
新书推荐:
我的新书《从企业级开发到云原生微服务: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)
多谢大家支持。