SpringBoot 手动配置 @Enable 的秘密
Posted Java知音_
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringBoot 手动配置 @Enable 的秘密相关的知识,希望对你有一定的参考价值。
点击关注公众号,实用技术文章及时了解
来源:Java日知录
在 Spring Boot
开发过程中,我们经常会看到使用 @EnableXXX
来激活我们某一个功能性的模块,通过类注解激活后我们就能使用所激活的配置给我们带来的功能。
今天我们就来探究一下这个 @EnableXXX
给我们做了哪些工作,或者我们应该怎么通过自定义的方式开发我们自己的功能模块。
演示环境
IntelliJ IDEA 2020.2.1 (Community Edition)
Maven 3.5.4
Spring Boot 2.1.1.RELEASE
走进源码
在 SpringBoot
中 @Enable
的实现方式用两种。
一种是注解驱动的方式,我们以 @EnableWebMvc
为例进行探究;
另外一种是接口编程的方式,我们以 @EnableCaching
为例进行探究。
1、注解驱动方式(@EnableWebMvc
)
在 Spring Boot
项目中,当我们可以使用 @EnableWebMvc
注解用来激活我们的 Spring MVC
相关的配置,接下来进入源码一探究竟。
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc
通过观察上面的源码,我们就可以大胆的猜测,其实使用 @EnableWebMvc
注解的作用就是导入 DelegatingWebMvcConfiguration.class
这个类,接下来我们就进入这个类看看。
@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport
........
@Override
protected void addInterceptors(InterceptorRegistry registry)
this.configurers.addInterceptors(registry);
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry)
this.configurers.addResourceHandlers(registry);
........
进入到这个类中我们发现了这个 @Configuration
注解,到这儿我们好像明白了写什么。首先这个 DelegatingWebMvcConfiguration
类继承了 WebMvcConfigurationSupport
类,重写了里面的关于 WebMvc
的相关配置,然后作为一个配置类加载到我们的 Spring
容器中。至此来实现启动(激活)WebMvc
模块。
2、接口编程的方式(@EnableCaching
)
在 Spring Boot
项目中,当我们可以使用 @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 Ordered.LOWEST_PRECEDENCE;
这里 @EnableCaching
同样是使用 @Import
导入了一个配置类,而它导入的是 CachingConfigurationSelector
,接着我进入这个类看一看。
public class CachingConfigurationSelector extends AdviceModeImportSelector<EnableCaching>
.....
@Override
public String[] selectImports(AdviceMode adviceMode)
switch (adviceMode)
case PROXY:
return getProxyImports();
case ASPECTJ:
return getAspectJImports();
default:
return null;
.....
发现其实这个类没有被注解标注,但是它继承了 AdviceModeImportSelector<enablecaching>
,而这个类又继承了 ImportSelector
,并且我们可以看看 ImportSelector
的代码:
public interface ImportSelector
/**
* Select and return the names of which class(es) should be imported based on
* the @link AnnotationMetadata of the importing @@link Configuration class.
*/
String[] selectImports(AnnotationMetadata importingClassMetadata);
这个类中只用一个方法,那就是 selectImports
。也就是说当我们重写了这个方法之后,我们可以在方法中添加自己的逻辑判断,来决定最后导入哪些配置类。这样就可以实现灵活的加载配置。这个方法的返回值 String[]
里面存放的是所有复合条件的配置类的全路径信息。
自定义实现
通过上面的分析我们已经完成了对 @EnableXXX
套路的了解,接下来我们自己动手实现下。首先需要准备一个 Spirng Boot
的项目,这里我已经准备好了。
1、注解驱动方式的自定义实现
根据我们分析源码的步骤我们首先需要准备一个配置类。接下来在 configuration
包下,创建一个 HelloConfiguration
。代码如下:
/**
* Hello模块的配置
*/
@Configuration
public class HelloConfiguration
@Bean
public String hello() // method name is bean name
System.out.println("Bean : hello is loading.");
return "hello word !";
这里被 @Bean
标注的方法,方法名会作为 bean
对象的名称。而且当该 bean
被加载的时候我们还会在控制台输出一段话 Bean : hello is loading.
。
配置类我们已经准备好了,接下来我们在 annotation
包中编写激活配置的注解。
/**
* 激活Hello模块配置
*
* @author Jerome Zhu
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(HelloConfiguration.class) // 模块装配:注解驱动实现
public @interface EnableHello
最后我们在 bootstrap
包中编写验证我们 @EnableHello
模块的启动类。
/**
* 验证自定义 @link EnableHello 模块化装配
*
* @author Jerome Zhu
*/
@EnableHello
public class EnableHelloBootstrap
public static void main(String[] args)
ConfigurableApplicationContext context = new SpringApplicationBuilder(EnableHelloBootstrap.class)
.web(WebApplicationType.NONE)
.run(args);
String helloBean = context.getBean("hello", String.class);
System.out.println("hello Bean: " + helloBean);
context.close();
我们在我们启动类上标注了 @EnableHello
来激活我们的 Hello
模块,并且在 Spring Boot
项目启动后,获取到了应用的上下文 ConfigurableApplicationContext
。然后我们根据我们注入的 bean
的名字 hello
来获取 bean
,接着打印 bean
的内容,最后关闭上下文。
我们启动程序后,可以在控制台中看到这样两行输出:
Bean : hello is loading.
hello Bean: hello word !
这刚好就是我们配置的内容,到这儿我们就完成了基于注解驱动方式激活(启动)配置。
2、接口编程方式自定义实现
根据我们读过源码后,我们首先最重要的是有一个继承 ImportSelector
的实现类。在 annotation
包中创建一个 HelloImportSelector
配置类。
/**
* Hello @link ImportSelector 的实现
*/
public class HelloImportSelector implements ImportSelector
private final String key = "jerome";
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata)
if ("jerome".equals(key))
return new String[]HelloJeromeConfiguration.class.getName();
return new String[]HelloConfiguration.class.getName();
这里为了体现出 selectImports
方法的作用,我们在本类中添加一个 key
字段。当 key
的值为 jerome
的时候我们去加载 HelloJeromeConfiguration
这个配置类。首先看一个这个配置类的内容。
/**
* Hello模块的配置
*
* @author Jerome Zhu
*/
@Configuration
public class HelloJeromeConfiguration
@Bean
public String hello() // method name is bean name
System.out.println("Bean : hello is loading.");
return "hello jerome !";
加载这个配置类后 bean
的名字还是 hello
但是内容变成了 hello jerome !
。接着我们对 @EnableHello
注解进行改造改造成 @EnableHellos
。
/**
* 激活Hellos模块配置
*
* @author Jerome Zhu
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(HelloImportSelector.class) // 模块装配:接口驱动实现 优点可选bean
public @interface EnableHellos
这里使用了 HelloImportSelector
来实现我们的模块装配。
这里
@EnableHellos
可能不符合命名规范,这里只做演示使用,不要喷我。
最后我们在 bootstrap
包中编写验证我们 @EnableHello
模块的启动类。
/**
* 验证自定义 @link EnableHellos 模块化装配
*
* @author Jerome Zhu
*/
@EnableHellos
public class EnableHellosBootstrap
public static void main(String[] args)
ConfigurableApplicationContext context = new SpringApplicationBuilder(EnableHellosBootstrap.class)
.web(WebApplicationType.NONE)
.run(args);
String helloBean = context.getBean("hello", String.class);
System.out.println("hello Bean: " + helloBean);
context.close();
这里和基于注解驱动方式激活(启动)配置的验证方法一样,我就是直接拷贝的,主要修改了 @EnableHellos
这个激活注解。
我们启动程序后,可以在控制台中看到这样两行输出:
Bean : hello is loading.
hello Bean: hello jerome !
这刚好就是我们配置的内容,到这儿我们就完成了基于接口编程方式激活(启动)配置。
总结
我们通过上面了解了 @EnableXXX
的两种实现方式。其中基于注解驱动方式激活(启动)配置的方式是相对方便的一个实现,需要激活什么就直接导入该配置类即可;而基于接口编程方式激活(启动)配置的方式相对更加灵活,可以根据自定义的规则来选择激活哪些配置类,不激活哪些配置类,这是一种比较灵活的方式,方便我们对其进行扩展。
总之这两种方式都是手动激活的方式,换言之我们需要在启动类上添加 @Enable***
的注解,来手动激活配置,这种方式在某些场景并不是很方便。
推荐
PS:因为公众号平台更改了推送规则,如果不想错过内容,记得读完点一下“在看”,加个“星标”,这样每次新文章推送才会第一时间出现在你的订阅列表里。点“在看”支持我们吧!
以上是关于SpringBoot 手动配置 @Enable 的秘密的主要内容,如果未能解决你的问题,请参考以下文章
SpringBoot 高级 原理分析 -- @Enable*注解@Import注解
SpringBoot:如何书写一个自定义的Enable*注解
[转] Spring Boot 自动配置之@Enable* 与@Import注解