博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
如何开发自己的Spring Boot Starter
阅读量:5960 次
发布时间:2019-06-19

本文共 6118 字,大约阅读时间需要 20 分钟。

我们在使用 Spring Boot 的过程中,往往都是在pom.xml里加了一系列的依赖,然后启支一个包含main方法的Application,一切就OK啦。给你我的感觉,就像是自己要动手做个菜,自己不再需要准备每一部分的原材料,直接购买包装好的一份菜的原料,下锅即可

那我们详细看下,这份「包装好」的原料中,到底做了些什么。

添加Starter依赖

这里添加的依赖,除了我们之前在Maven中熟悉的之外,还有一些都是长这个样子:

名为xxx-starter,比如

org.springframework.boot
spring-boot-starter-web
org.mybatis.spring.boot
mybatis-spring-boot-starter
1.3.2
复制代码

具体这些starter是怎么起作用的呢,他们什么时候开始工作的?

一切都要从入口处说起。我们以上面的starter为例,看到这个mybatis的starter,其对应的pom中,包含这些依赖

org.springframework.boot
spring-boot-starter
org.springframework.boot
spring-boot-starter-jdbc
org.mybatis.spring.boot
mybatis-spring-boot-autoconfigure
org.mybatis
mybatis
org.mybatis
mybatis-spring
复制代码

我们看到,相当于我们添加了一个Starter的依赖,其背后会引入许多其定义的其他依赖,通过 Maven 的传递依赖,这些都会被自动添加了进来。

自动配置

相比传统的依赖,我们看到其中包含这样一个:mybatis-spring-boot-autoconfigure,这也是每个Starter的秘密所在:「AutoConfigure」

它会在实现时,考虑应用中的其他部分因素,「推断」你所需要的 Spring 配置。

在Spring Boot中,我们最大的感受是配置仿佛都被做好了,直接使用即可,这就是

spring-boot-autoconfigure. 每个starter都有一个名为spring.factories
的文件,存放在META-INF目录下,其中的内容类似下面这个样子:

# Auto Configureorg.springframework.boot.autoconfigure.EnableAutoConfiguration=\org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration复制代码

所有需要自动配置的Class,都需要配置成key是EnableAutoConfiguration的。

我们来看类的内部

@Configuration@ConditionalOnClass({SqlSessionFactory.class, SqlSessionFactoryBean.class})@ConditionalOnBean({DataSource.class})@EnableConfigurationProperties({MybatisProperties.class})@AutoConfigureAfter({DataSourceAutoConfiguration.class})public class MybatisAutoConfiguration {
复制代码

Class 之上, 有不少注解来标识,有几点需要关注的:

  • 其中有标准的 Spring 配置注解 @Configuration

  • 几个@ConditionalXX

  • 标识执行顺序的@AutoConfigureAfter

其中,@ConditionalOnClass 标识 SqlSessionFactory类存在时,执行该配置, @ConditionalOnBean标识DataSource Bean在 Spring Context时,执行配置。

这些spring.factories是怎么被识别的呢? 这就得夸下 Spring 的FactoriesLoader了。

看下官方文档说明

Auto-configuration classes are regular Spring {@link Configuration} beans. They are located using the {@link SpringFactoriesLoader} mechanism (keyed against this class).

Generally auto-configuration beans are {@link Conditional @Conditional} beans (most
often using {@link ConditionalOnClass @ConditionalOnClass} and
{@link ConditionalOnMissingBean @ConditionalOnMissingBean} annotations).

启动的时候,根据ClassLoader中的jar,扫描所有 spring.factories,将其中符合条件的过滤出来,执行对应的配置。重点可以关注下

AutoConfigurationImportFilter类,

protected List
getAutoConfigurationImportFilters() { return SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class, this.beanClassLoader); }复制代码
private List
filter(List
configurations, AutoConfigurationMetadata autoConfigurationMetadata) { long startTime = System.nanoTime(); String[] candidates = StringUtils.toStringArray(configurations); boolean[] skip = new boolean[candidates.length]; boolean skipped = false; for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) { invokeAwareMethods(filter); boolean[] match = filter.match(candidates, autoConfigurationMetadata); for (int i = 0; i < match.length; i++) { if (!match[i]) { skip[i] = true; skipped = true; } } } if (!skipped) { return configurations; } List
result = new ArrayList<>(candidates.length); for (int i = 0; i < candidates.length; i++) { if (!skip[i]) { result.add(candidates[i]); } } return new ArrayList<>(result); }public String[] selectImports(AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return NO_IMPORTS; } AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader .loadMetadata(this.beanClassLoader); AnnotationAttributes attributes = getAttributes(annotationMetadata); List
configurations = getCandidateConfigurations(annotationMetadata, attributes); configurations = removeDuplicates(configurations); Set
exclusions = getExclusions(annotationMetadata, attributes); checkExcludedClasses(configurations, exclusions); configurations.removeAll(exclusions); configurations = filter(configurations, autoConfigurationMetadata); fireAutoConfigurationImportEvents(configurations, exclusions); return StringUtils.toStringArray(configurations); }复制代码

经过这里的执行之后, filter方法把符合条件的过滤出来了。

创建自定义Starter

经过上面两步,我们大概知道 Starter的工作原理。有时候,我们需要对外提供一些工具组件时,也想以 Starter 的形式提供出来,供别人使用。步骤也还算清晰,照葫芦画瓢。

  • 先创建自己的模块

  • 增加需要用到的依赖

  • 创建对应的 AutoConfiguration

  • 创建META-INF/spring.factories 文件

此时,就不需要再将 Spring Boot 做为 Parent依赖,在单独的依赖中增加

org.springframework.boot
spring-boot-autoconfigure
2.0.6.RELEASE
org.springframework.boot
spring-boot-starter
2.0.6.RELEASE
复制代码

AutoConfiguration类也简单,照上面的创建一个

@Configuration@ConditionalOnClass(HelloService.class)public class HelloServiceAutoConfiguration {
复制代码

然后,增加文件

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.example.demo.HelloServiceAutoConfiguration复制代码

在需要这个服务的地方,直接引入依赖就OK啦。

转载于:https://juejin.im/post/5cefc499f265da1bc5524852

你可能感兴趣的文章
3.1
查看>>
校验表单如何摆脱 if else ?
查看>>
<气场>读书笔记
查看>>
Centos下基于Hadoop安装Spark(分布式)
查看>>
3D地图的定时高亮和点击事件(基于echarts)
查看>>
mysql开启binlog
查看>>
设置Eclipse编码方式
查看>>
分布式系统唯一ID生成方案汇总【转】
查看>>
并查集hdu1232
查看>>
Mysql 监视工具
查看>>
从前后端分离到GraphQL,携程如何用Node实现?\n
查看>>
Linux Namespace系列(09):利用Namespace创建一个简单可用的容器
查看>>
博客搬家了
查看>>
Python中使用ElementTree解析xml
查看>>
jquery 操作iframe、frameset
查看>>
解决vim中不能使用小键盘
查看>>
jenkins权限管理,实现不同用户组显示对应视图views中不同的jobs
查看>>
我的友情链接
查看>>
CentOS定时同步系统时间
查看>>
批量删除用户--Shell脚本
查看>>