如何手写一个自己的SpringBoot起步依赖
在使用springboot做脚手架开发时,springboot为我们提供了极大的便利,特别是jar包的版本和各种组件的自动配置。本章节就来研究下Springboot中组件自动配置的原理,以及如何去实现一个自己的SpringBoot组件给别人使用。
SpringBoot自动配置基础
SpringBoot自动配置中,会用到两个核心的基础注解,@Import注解和@Conditional注解。
-
@Import注解
@Import注解是spring的一种声明bean的方式,它可以直接指定类型来声明bean,也可以指importSelector,或者ImportBeanDefinitionRegistrar来声明bean。
-
@Conditional注解
@Conditional注解用于配置类中,当满足特定条件后,才会注册bean,其中条件是否满足,由指定的Condition来判断。
@Import注解和@Conditional的具体示例见 Spring框架核心注解用例 (https://blog.youkuaiyun.com/gruelxsp/article/details/103400787)。
SpringBoot自动配置原理
在了解了@Import注解和@Conditional注解后,我们可以看下源码,理解SpringBoot自动配置是如何实现的。
-
@SpringBootApplication注解
使用SpringBoot的工程时,我们知道在启动类上,要加上@SpringBootApplication注解,比如:
@SpringBootApplication public class SpringStackApplication { public static void main(String[] args) { SpringApplication.run(SpringStackApplication.class, args); } }
那么这个@SpringBootApplication注解究竟是起了什么作用呢?打开它的源码:
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited //@SpringBootConfiguration 表明它是一个配置类 @SpringBootConfiguration //@EnableAutoConfiguration 这个注解中实现了自动配置功能 @EnableAutoConfiguration @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) public @interface SpringBootApplication {
通过源码我们发现,@SpringBootApplication注解被另外两个@SpringBootConfiguration、@EnableAutoConfiguration 注解了。
@SpringBootConfiguration注解很简单,它被@Configuration注解了,表明是一个配置类。
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Configuration public @interface SpringBootConfiguration { }
因此,在@SpringBootApplication注解的启动类中,也是配置bean的,不过通常我们不会这么去做。
-
@EnableAutoConfiguration注解
另外一个@EnableAutoConfiguration注解就比较关键了,它是真正实现自动配置的入口:
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited //@AutoConfigurationPackage 包含这个注解的类的包应该被扫描注册。 @AutoConfigurationPackage //@Import AutoConfigurationImportSelector 这就是自动配置的实现 @Import(AutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration {
通过源码我们可以发现@EnableAutoConfiguration又被另外两个@AutoConfigurationPackage和@Import(AutoConfigurationImportSelector.class)注解了,其中@AutoConfigurationPackage比较简单,它实现的是使用这个注解的类,其所在的包下,所有类都会被扫描注册。
/** * Indicates that the package containing the annotated class should be registered with * {@link AutoConfigurationPackages}. */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @Import(AutoConfigurationPackages.Registrar.class) public @interface AutoConfigurationPackage { }
这也是我们使用SpringBoot时,不用配置@ComponentScan也能实现和启动类同包(及其子包)下的组价也会自动被扫描注册的原因,因此通常我们的启动类会放置到顶层包中。比如:
-
@Import(AutoConfigurationImportSelector.class)
最最关键的是@