在spring-boot框架中@EnableAutoConfiguration 开启自动扫描装配Bean
实现方式
- 注解方式
- 编程方式
背景
在学习SpringBoot的时候,我们会使用到@Enable***注解的地方,使用上也都是加在@Configuration 类注解的类上面,比如:
(1)@EnableAutoConfiguration 开启自动扫描装配Bean
(2)@EnableScheduling 开启计划任务的支持
(3)@EnableTransactionManagement 开启注解式事务的支持。
(4)@EnableCaching开启注解式的缓存支持。
(5)@EnableAspectJAutoProxy 开启对AspectJ自动代理的支持,
(6) @EnableAsync 开启异步方法的支持
(7) @EnableWebMvc 开启Web MVC的配置支持。
(8) @EnableConfigurationProperties 开启对@ConfigurationProperties注解配置Bean的支持。
(9)@EnableJpaRepositories 开启对Spring Data JPA Repository的支持。
查看@Enable的源码
查看这些注解的实现,我们发现每一个注解都有一个 @Import 注解。@Import注解在4.2之前只支持导入配置类,在4.2,@Import注解支持导入普通的java类,并将其声明成一个bean。这也说明了,自动开启的实现,其实是导入了一些配置类。
@EnableWebMvc采用注解驱动方式
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}
@EnableCaching采用接口编程方式
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({CachingConfigurationSelector.class})
public @interface EnableCaching {
boolean proxyTargetClass() default false;
AdviceMode mode() default AdviceMode.PROXY;
int order() default 2147483647;
}
public class CachingConfigurationSelector extends AdviceModeImportSelector<EnableCaching> {
......
public CachingConfigurationSelector() {
}
public String[] selectImports(AdviceMode adviceMode) {
switch(adviceMode) {
case PROXY:
return this.getProxyImports();
case ASPECTJ:
return this.getAspectJImports();
default:
return null;
}
}
.....
}
- 首先@EnableCaching需要@Import一个CachingConfigurationSelector类
- CachingConfigurationSelector又继承AdviceModeImportSelector
- AdviceModeImportSelector又实现了ImportSelector
- 所有,当我们自定以一个@Enable模块时需要ImportSelector的实现类
自定义@Enable模块
基于注解驱动实现
定义给一个配置类
@Configuration
public class MyConfiguration {
/**
* 方法名为 Bean 名称
* @return
*/
@Bean
public String test() {
return "自定义配置类";
}
}
使用注解的方式,@Import需要导入一个配置类。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({MyConfiguration.class})
public @interface EnableMyConfig {
}
@SpringBootApplication
@EnableMyConfig
public class TestApplication {
public static void main(String[] args){
SpringApplication app = new SpringApplication(TestApplication.class);
// app.setWebEnvironment(false);
ConfigurableApplicationContext context =app.run(args);
String test = context.getBean("test",String.class);
System.out.println("bean是否存在--->"+test);
}
}
测试时TestApplication类跟MyConfiguration类要放在不同包下,或者不使用@SpringBootApplication,使用@Configuration+@EnableAutoConfiguration。
@SpringBootApplication=@Configuration+@EnableAutoConfiguration+@ComponentScan,其中扫描包的范围为启动类所在包和子包,不包括第三方的jar包。如果我们需要扫描通过maven依赖添加的jar,我们就要单独使用@ComponentScan注解扫描第三方包。
基于接口驱动实现
配置类
public class MyConfiguration2 {
/**
* 方法名为 Bean 名称
* @return
*/
@Bean
public String test2() {
return "自定义配置类";
}
}
自定义ImportSelector的实现类。
public class MyImportSelector2 implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
// 返回一个自定义类
// 使用MyImportSelector导入MyConfiguration,而不是直接导入MyConfiguration
return new String[]{MyConfiguration2.class.getName()};
}
}
自定义@Enable
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({MyImportSelector2.class})
public @interface EnableMyConfig2 {
}
测试
@Configuration
@EnableAutoConfiguration
@EnableMyConfig2
public class EnableApplication {
public static void main(String[] args){
SpringApplication app = new SpringApplication(EnableApplication.class);
// app.setWebEnvironment(false);
ConfigurableApplicationContext context =app.run(args);
String test = context.getBean("test2",String.class);
System.out.println("bean是否存在--->"+test);
}
}
-
运行顺序
首先,EnableTestBootstrap启动,之后根据@EnableMyConfig注解,找到MyImportSelector类,找到selectImports方法,进行加载“test”bean操作。
-
对比
这种实现方式,我们可以在装载bean中间进行一些操作,相对注解实现方式比较自由,编程实现方式可以有一些弹性操作。