@EnableAutoConfiguration的官方解释:The second class-level annotation is @EnableAutoConfiguration. This annotation tells Spring Boot to “guess” how you want to configure Spring, based on the jar dependencies that you have added. Since spring-boot-starter-web added Tomcat and Spring MVC, the auto-configuration assumes that you are developing a web application and sets up Spring accordingly.
大概意思是说springboot会将那些标有@Enable*注解的配置,自动的注入到spring容器中,今天要讨论的是@Enable注入的几种方式
一、直接使用Import注入配置
创建HelloWorldConfiguration注解,并且声明一个bean
public class HelloWorldConfiguration {
@Bean
public String helloWorld() {
return "hello world";
}
}
创建注解EnableHelloWorld,直接Import HelloWorldConfiguration
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(HelloWorldConfiguration.class)
//@Import(HelloWorldImportSelector.class)
public @interface EnableHelloWorld {
}
创建启动类EnableHelloWorldBootstrap ,获取helloWorld这个Bean
@EnableHelloWorld
public class EnableHelloWorldBootstrap {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(EnableHelloWorldBootstrap.class, args);
String helloWorld = context.getBean("helloWorld", String.class);
System.out.println("hello world bean:" + helloWorld);
}
}
运行这个bootstrap,可以看到获取helloWorld这个bean
二、基于ImportSelector实现
ImportSelector Spring会把实现ImportSelector接口的类中的SelectImport方法返回的值注入到Spring容器中。这个方法的返回值必须是一个class的全类名的String[],创建HelloWorldImportSelector
/**
* HelloWorld {@link ImportSelector}
*/
public class HelloWorldImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
return new String[]{HelloWorldConfiguration.class.getName()};
}
}
修改EnableHelloWorld注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
//@Import(HelloWorldConfiguration.class)
@Import(HelloWorldImportSelector.class)
public @interface EnableHelloWorld {
}
再次运行bootstrap这个类,可以看到同样的结果
总结,两种方式都可以实现@Enable的模块化装配,如果有需求需要条件注入,第一种就需要配合@ConditionXXX或者@Profile实现;第二种方式可以通过编码的方式去实现
三、基于ImportBeanDefinitionRegistrar实现
ImportBeanDefinitionRegistrar registerBeanDefinitions方法的参数有一个BeanDefinitionRegistry, BeanDefinitionRegistry可以用来往spring容器中注入bean 如此,我们就可以在registerBeanDefinitions方法里面动态的注入bean
实现一个HelloWorldImportBeanDefinitionRegistrar
public class HelloWorldImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
BeanDefinitionBuilder bdb = BeanDefinitionBuilder.rootBeanDefinition(HelloWorldConfiguration.class);
registry.registerBeanDefinition(HelloWorldConfiguration.class.getName(), bdb.getBeanDefinition());
}
}
修改EnableHelloWorld注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
//@Import(HelloWorldConfiguration.class)
//@Import(HelloWorldImportSelector.class)
@Import(HelloWorldImportBeanDefinitionRegistrar.class)
public @interface EnableHelloWorld {
}
再次运行bootstrap这个类,可以看到同样的结果