教你定制标准Spring Boot starter,看起来如春风般柔和

springboot自定义starter(三) springboot自定义starter 阅读详情

写在前面

我们每次构建一个 Spring 应用程序时,我们都不希望从头开始实现具有「横切关注点」的内容;相反,我们希望一次性实现这些功能,并根据需要将它们包含到任何我们要构建的应用程序中

横切关注点

横切关注点: 指的是一些具有横越多个模块的行为 (来自维基百科的介绍)说白了就是多个项目或模块都可以用到的内容,比如一个 SDK

在Spring Boot中,用于表示提供这种横切关注点的模块的术语是 starter,通过依赖 starter 可以轻松使用其包含的一些功能特性,无论你的工作中是否会构建自己的 starter,你都要具有构建 「starter」的思想,本文将结合 Spring Boot 官方标准构建一个简单的 starter

自定义 starter

在我们深入了解如何自定义 starter 之前,为了更好的理解我们每一步在干什么,以及 starter 是如何起作用的,我们先从宏观角度来看 starter 的结构组成到底是什么样的

通常一个完整的 starter 需要包含下面两个组件:

  1. Auto-Configure Module
  2. Starter Module

如果你看下面这两个组件的解释有些抽象,大概了解一下,阅读完该文章回看这里就会豁然开朗了

Auto-Configure Module

Auto-Configure Module (自动配置模块) 是包含自动配置类的 Maven 或 Gradle 模块。通过这种方式,我们可以构建可以自动贡献于应用程序上下文的模块,以及添加某个特性或提供对某个外部库的访问

Starter Module

Spring Boot Starter 是一个 Maven 或 Gradle 模块,其唯一目的是提供 "启动" 某个特性所需的所有依赖项。可以包含一个或多个 Auto-Configure Module (自动配置模块)的依赖项,以及可能需要的任何其他依赖项。这样,在Spring 启动应用程序中,我们只需要添加这个 starter 依赖就可以使用其特性

⚠️: Spring 官方参考手册建议将自动配置分离,并将每个自动配置启动到一个独立的 Maven 或 Gradle 模块中,从而将自动配置和依赖项管理分离开来。如果你没有建立一个供成千上万用户使用的开源库,也可以将二者合并到一个 module 中You may combine the auto-configuration code and the dependency management in a single module if you do not need to separate those two concerns

命名

来自 Spring 官方的 starter 都是 以 spring-boot-starter 开头,比如:

  • spring-boot-starter-web
  • spring-boot-starter-aop

如果我们自定义 starter 功能名称叫acme,那么我们的命名是这样的:

  • acme-spring-boot-starter
  • acme-spring-boot-autoconfigure

如果 starter 中用到了配置 keys,也要注意不要使用 Spring Boot 使用的命名空间,比如(server,management,spring)

Parent Module 创建

先来全局看一下项目结构:一级目录结构:

.
├── pom.xml
├── rgyb-spring-boot-autoconfigure
├── rgyb-spring-boot-sample
└── rgyb-spring-boot-starter

二级目录结构:

.
├── pom.xml
├── rgyb-spring-boot-autoconfigure
│ ├── pom.xml
│ └── src
├── rgyb-spring-boot-sample
│ ├── pom.xml
│ └── src
└── rgyb-spring-boot-starter
 ├── pom.xml
 └── src

创建一个空的父亲 Maven Module,主要提供依赖管理,这样 SubModule 不用单独维护依赖版本号,来看 pom.xml 内容:

<dependencyManagement>
 <dependencies>
 <dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-dependencies</artifactId>
 <version>${spring-boot.version}</version>
 <type>pom</type>
 <scope>import</scope>
 </dependency>
 </dependencies>

 <!-- 添加其他全局依赖管理到这里,submodule默认不引入这些依赖,需要显式的指定 -->
</dependencyManagement>

Auto-Configure Module 构建

新建类 GreetingAutoConfiguration

@Configuration
public class GreetingAutoConfiguration {

 @Bean
 public GreetingService greetingService(GreetingProperties greetingProperties){
 return new GreetingService(greetingProperties.getMembers());
 }
}

我们用 @Configuration 注解标记类 GreetingAutoConfiguration,作为 starter 的入口点。这个配置包含了我们需要提供starter特性的所有 @Bean 定义,在本例中,为了简单阐述问题,我们只将 GreetingService Bean 添加到应用程序上下文

GreetingService 内容如下:

@AllArgsConstructor
public class GreetingService {

 private List<String> members = new ArrayList<>();

 public void sayHello(){
 members.forEach(s -> System.out.println("hello " + s));
 }
}

在 resources 目录下新建文件 META-INF/spring.factories (如果目录 META-INF 不存在需要手工创建),向文件写入内容:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
 top.dayarch.autoconfigure.GreetingAutoConfiguration

Spring 启动时会在其 classpath 中所有的 spring.factoreis 文件,并加载里面的声明配置,GreetingAutoConfiguration 类就绪后,我们的 Spring Boot Starter 就有了一个自动激活的入口点

到这里这个 "不完全的 starter" 已经可以使用了。但因为它是自动激活的,为了个让其灵活可用,我们需要让其按照我们的意愿来激活使用,所以我们需要条件注解来帮忙

条件配置

为类添加两个条件注解:

@Configuration
@ConditionalOnProperty(value = "rgyb.greeting.enable", havingValue = "true")
@ConditionalOnClass(DummyEmail.class)
public class GreetingAutoConfiguration {
 ...
}
  • 通过使用 @ConditionalOnProperty 注解,我们告诉 Spring,只有属性 rgyb.greeting.enable 值被设置为 true 时,才将 GreetingAutoConfiguration (以及它声明的所有 bean ) 包含到应用程序上下文中
  • 通过使用 @ConditionalOnClass 注解,我们告诉Spring 只有类 DummyEmail.class 存在于 classpath 时,才将 GreetingAutoConfiguration (以及它声明的所有 bean ) 包含到应用程序上下文中

多个条件是 and/与的关系,既只有满足全部条件时,才会加载 GreetingAutoConfiguration

如果你对条件注解的使用还不是很明确,可以查看我之前的文章: @Conditional注解,灵活配置 Spring Boot

配置属性管理

上面使用了 @ConditionalOnProperty 注解,实际 starter 中可能有非常多的属性,所以我们需要将这些属性集中管理:

@Data
@ConfigurationProperties(prefix = "rgyb.greeting")
public class GreetingProperties {

 /**
 * GreetingProperties 开关
 */
 boolean enable = false;

 /**
 * 需要打招呼的成员列表
 */
 List<String> members = new ArrayList<>();
}

我们知道这些属性是要在 application.yml 中使用的,当我们需要使用这些属性时,为了让 IDE 给出更友好的提示,我们需要在 pom.xml 中添加依赖:

<dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-configuration-processor</artifactId>
 <optional>true</optional>
</dependency>

这样当我们 mvn compile 时,会在生成一个名为 spring-configuration-metadata.json JSON 文件,文件内容如下:

生成的内容在接下来的内容中用到,且看

提升启动时间

对于类路径上的每个自动配置类,Spring Boot 必须计算 @Conditional… 条件值,用于决定是否加载自动配置及其所需的所有类,根据 Spring 启动应用程序中 starter 的大小和数量,这可能是一个非常昂贵的操作,并且会影响启动时间,为了提升启动时间,我们需要在 pom.xml 中添加另外一个依赖:

<dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-autoconfigure-processor</artifactId>
 <optional>true</optional>
</dependency>

这个注解会生成一个名为 spring-autoconfigure-metadata.properties Property 文件,其内容如下:

这样,Spring Boot 在启动期间读取这些元数据,可以过滤出不满足条件的配置,而不必实际检查这些类,提升启动速度

到这里关于 Auto-Configure Module 就构建完了,我们需要继续完成 Starter Module 的构建

Starter Module 构建

Starter Module 的构建很简单了,你可以认为它就是一个空 module,除了依赖 Auto-Configure Module,其唯一作用就是为了使用 starter 功能特性提供所有必须依赖,所以我们为 starter module 的 pom.xml 文件添加如下内容:

<dependencies>
 <dependency>
 <groupId>top.dayarch.learnings</groupId>
 <artifactId>rgyb-spring-boot-autoconfigure</artifactId>
 <version>1.0.0.RELEASE</version>
 </dependency>

 <!-- 在此处添加其他必要依赖,保证starter可用 -->
</dependencies>

同样在 resources 目录下新建文件 META-INF/spring.providers , 其内容如下:

providers: rgyb-spring-boot-autoconfigure

该文件主要作用是说明 starter module 的依赖信息,多个依赖以逗号分隔就好,该文件不会影响 starter 的使用,可有可无

Starter Module 就可以这么简单,将两个 module 分别 mvn install 到本地 Maven Repository,接下来我们创建 sample module 引入这个 starter 依赖时就会从本地 Maven Repository 中拉取

创建 Sample Module

我们可以通过 Spring Initializr 正常初始化一个 Spring Boot 项目 (rgyb-spring-boot-sample),引入我们刚刚创建的 starter 依赖,在 sample pom.xml 中添加依赖:

<dependency>
 <groupId>top.dayarch.learnings</groupId>
 <artifactId>rgyb-spring-boot-starter</artifactId>
 <version>1.0.0.RELEASE</version>
</dependency>

接下来配置 application.yml 属性

rgyb:
 greeting:
 enable: true
 members:
 - 李雷
 - 韩梅梅

在我们配置 YAML 的时候,会出现下图的提示,这样会更友好,当然为了规范,属性描述最好也用英文描述,这里为了说明问题用了中文描述:

编写测试类

我们编写测试用例:

@Autowired(required = false)
private GreetingService greetingService;

@Test
public void testGreeting() {
 greetingService.sayHello();
}

测试结果如下:

hello 李雷
hello 韩梅梅

总结

到这里完整的 starter 开发就结束了,希望大家了解其构建过程,目录结构及命名等标准,这样有相应的业务需求时都可以开发自己的 starter 被其他人应用起来

starter 开发好了,别人可以手动添加依赖引入 starter 的相关功能,那我们如何像 Spring Initializr 一样,通过下来菜单选择我们的 starter 呢,这样直接初始化好整个项目,接下来的文章我们会模仿 Spring Initializr 自定义我们自的 Initializr

知识点说明

Dependency optinal

为什么 Auto-Configure Module 的 dependency 都是 optional = true 呢?这涉及到 Maven 传递性依赖的问题,详情请看 Maven 依赖传递性透彻理解

spring.factories

Spring Boot 是如何加载这个文件并找到我们的配置类的下图是 Spring Boot 应用程序启动的调用栈的一部分,我添加了断点:

打开 SpringFactoriesLoader 类,映入眼帘的就是这个内容:

这两张图应该足够说明问题了,是 SPI 的一种加载方式,更细节的内容请大家自己去发现吧

实际案例

这里推荐查看 mybatis-spring-boot-starter 这个非 Spring 官方的案例,从中我们:

  • 模仿其目录结构
  • 模仿其设计理念
  • 模仿其编码规范

 

关于spring boot小编准备了一篇详细的pdf文档,免费送给粉丝们,关注+转发+评论后私信“文档”免费获取。

Spring Boot手动封装starter 解压后先打开file-spring-boot-starter进行install,然后再用file-demo测试 立即下载

相关推荐

scrapy - 美团民宿 实战练习

目录结构 items.py import scrapy # 民俗名称,地区,价格,房间类型及数量,床的数量,可住几人 class MeituanItem(scrapy.Item): # define the fields for your item here like: # name = scrapy.Field() title = scrapy.Field() place = scrapy.Field() price = scrapy.F...

小刘的博客 2664

Spring配置文件总结

1.基本配置:xml version="1.0" encoding="UTF-8"?>beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springfra

漠海林峰 4607

用Python搞定超效率SBM模型:从数据清洗到结果可视化全流程指南

本文详细介绍了如何使用Python实现超效率SBM模型,从数据清洗到结果可视化的全流程指南。超效率SBM模型作为传统DEA的进化版本,能有效处理非期望产出(如环境污染)并对高效单元进行精细排序。通过实战案例和代码示例,帮助读者掌握这一先进模型的Python实现技巧,提升效率评估的准确性和可视化效果。

silver的专栏 650

springboot-starter中的SPI 机制

SPI的全称是Service Provider Interface, 直译过来就是"服务提供接口", 听起来挺别扭的, 所以我试着去就将它翻译为"服务提供商接口"吧. 我们都知道, 一个接口是可以有很多种实现的. 例如搜索,可以是搜索系统的硬盘,也可以是搜索数据库.系统的设计者为了降低耦合,并不想在硬编码里面写死具体的搜索方式,而是希望由服务提供者来选择使用哪种搜索方式, 这个时候就可以选择使用SPI机制. SPI机制被大量应用在各种开源框架中,例如: 大家都熟悉的dubbo中的ExtensionLoad

yangyangrenren的专栏 1219

S型速度曲线C程序实现

S型速度曲线C语言程序实现 前言 S型曲线相较于梯形速度曲线具有运行更加平稳的特点,S型曲线共有八种运行情况,感兴趣可以查阅相关文献 代码段 #include <stdio.h> #include <math.h> #define FP64 double int main(void) { /**************************** 定义相关变量(需要映射到PLC寄存器才能进行监控) ***********************/ FP6

LSX312441548的博客 8392

想发故障诊断论文?手把手教你用CWRU数据集复现第一个Baseline模型

本文提供了一份基于CWRU轴承数据集的故障诊断Baseline模型实战指南,手把手教你从数据准备到模型构建的全流程。通过详细的Python代码示例和学术级实验设计,帮助初学者快速复现第一个故障诊断模型,为发表高质量论文奠定基础。

weixin_28681255的博客 428

废除了providers而用provider

开发时发现viewModel = new ViewModelProvider(this).get(ViewModel.class);这种构造方法已经找不到了,官方文档也没有更新,后查阅资料发现可以这样写: myViewModel=new ViewModelProvider(this,new ViewModelProvider.NewInstanceFactory()).get(MyViewModel.class); ...

weixin_39494124的博客 213

qcc51xx如何配置spdif输入

qcc51xx如何配置spdif输入。

Alex_886的博客 1373

spring 今儿学到的一些注解与依赖(provider)

providerprovider组成依赖配置文件application.yml注解 provider组成 依赖 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/X...

qq_43309933的博客 1058

昇腾910安装驱动出错,降低Centos7.6的内核版本

Centos7.6 启动内核修改,解决昇腾910安装驱动错误的问题。

深蓝 3300

【开发必备插件】iframe嵌套报“拒绝连接请求”的本地解决方法

关键词:iframe 拒绝连接、X-Frame-Options、Chrome 插件、前端调试、Allow X-Frame-Options前几天我在本地项目里调试一个第三方网站的嵌入页面时,遇到了一个非常经典的报错:xxx.com 拒绝了我们的连接请求。熟悉的老前端们一眼就知道——这是。但对于日常开发来说,我们经常需要在本地测试 iframe 嵌套外部页面(比如嵌第三方登录页、支付页、可视化报表系统等)。而线上站点配置了或DENY时,就会直接导致 iframe 加载失败。

代码简单说 Vue、JAVA、PHP、Node.js 熟练运用,接口、架构、性能全搞定。 1542

spring-boot中的SPI 机制

SPI的全称是Service Provider Interface, 直译过来就是"服务提供接口", 听起来挺别扭的, 所以我试着去理解了一下, 就将它翻译为"服务提供商接口"吧. 我们都知道, 一个接口是可以有很多种实现的. 例如搜索,可以是搜索系统的硬盘,也可以是搜索数据库.系统的设计者为了降低耦合,并不想在硬编码里面写死具体的搜索方式,而是希望由服务提供者来选择使用哪种搜索方式, 这个时候...

weixin_34184561的博客 1万+

BAT007:批量为当前目录下的文件夹添加前缀或后缀

摘要:编写批处理程序,实现批量为当前目录下的文件夹添加前缀或后缀。

qq_31762031的博客 4052

西瓜书自学指南:从算法推导到项目实战的机器学习路线

机器学习通过大量带标签的数据学习输入与输出之间的映射,这一过程类似于人类认识猫并为其打上标签。掌握其核心原理,如线性回归、决策树、支持向量机等,是构建技术价值的基础。从经典教材《机器学习》(西瓜书)出发,系统梳理数学基础、算法推导与代码实现,能够帮助学习者在人脸识别项目开源代码复现、实验室机器学习服务器搭建等真实场景中快速落地。本文以西瓜书为主线,分享从全局框架到逐个击破的自学路线,覆盖环境配置、避坑技巧与心态方法,为希望建立扎实机器学习功底的人提供可执行的参考。

weixin_34417200的博客 688

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

工作中使用到的单词(软件开发)

1.エイリアス   alias 别名 powershell使用 get-help 命令时,会得到与此命令 相关(别名)的命令 2.プロキシ proxy 代 理 3.プロモート   promote 促进,提升   开发的系统新功能上线发布,有时会使用到这个词,比如 STプロモート 还有使用リリース这个词的。比如STリリース。个人认为两者含义相同。 4.見逃し み................................................................

sun0322 6万+

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

手把手教你定制标准 Spring Boot starter

写在前面我们每次构建一个 Spring 应用程序时,我们都不希望从头开始实现具有「横切关注点」的内容;相反,我们希望一次性实现这些功能,并根据需要将它们包含到任何我们要构建的应用程序中横切关注点横切关注点: 指的是一些具有横越多个模块的行为 (来自维基百科的介绍)说白了就是多个项目或模块都可以用到的内容,比如一个 SDK在Spring Boot中,用于表示提供这种横切关注点的模块的术语是star...

日拱一兵 965

从nacos-spring-boot-project角度全面看Springboot Starter

一、作用与原理 首先说说原理,我们知道使用一个公用的starter的时候,只需要将相应的依赖添加的Maven的配置文件当中即可,免去了自己需要引用很多依赖类,并且SpringBoot会自动进行类的自动配置。那么 SpringBoot 是如何知道要实例化哪些类,并进行自动配置的呢? 下面简单说一下。 首先,SpringBoot 在启动时会去依赖的starter包中寻找resources/MET...

FeelTouch Labs 2081

Sping Boot入门到实战之实战篇(一):实现自定义Spring Boot Starter——阿里云消息队列服务Starter...

  在Sping Boot入门到实战之入门篇(四):Spring Boot自动化配置这篇中,我们知道Spring Boot自动化配置的实现,主要由如下几部分完成: @EnableAutoConfiguration注解 SpringApplication类 spring-boot-autoconfigure jar包 spring.factories文件   官方提供...

477

[spring security]除了过滤器顺序,还特别需要注意的providers顺序

spring security对于用户身份的判断是通过一系列的过滤器来完成的,如果你采用的是自定义过滤器链的方式来实现自己的需求,那么需要特别注意过滤器链的顺序问题。一个较为典型的问题是:为什么我的用户是密码错误,但是却抛出用户不存在的异常呢?(而不是抛出身份检查失败异常)这就是因为配置的org.springframework.security.providers.ProviderManager中的providers顺序不合适导致的了,过滤器的检查,是一个链表的形式,如果当前的过滤器能匹配成功,那么则会停止

quzishen的专栏 3571

SpringCloud之服务的提供者(Provider)

a

897855609的博客 565

spring ObjectProvider 源码分析

在新spring框架(4.x系列)源码中经常可以看到ObjectProvider<T>的语法,而在度娘查找资料,你发现几乎找不到能讲清楚它来龙去脉的文章,下面将本着寻根溯源的态度去研究它。 //源自org.springframework.boot.autoconfigure.web.WebClientAutoConfiguration @Configuration @AutoCon...

布道 1万+

SpringCloud--register、provider

本篇文章是自己针对SpringCloud学的的总结。主要总结SpringCloud的服务注册、发现和消费。 一、服务的注册 在使用SpringCloud开发应用中,我们需要将所有的功能模块都注册到一个相同的容器,而这个容器就是我们下面看到的register。下面详解创建服务注册器的过程。 (1)创建一个SpringBoot工程。 由于SpringCloud是基于SpringBoot的分布式

ONROAD0612的博客 1861

spring security(SpringBoot)自定义Provider实现多种认证方式

转载请注明出处spring boot 实例之 多登录方式–碧波之心简书 接上一篇:spring boot 实例之 用户登录。经过对spring security再次分析,觉得上一篇的实现方式有些不合理。不应该把UsernamePasswordAuthenticationFilter给替换了。今天我们来优化一下。让登录的扩展更合理一些。 调整目录结构 原目录结构: 删除Sec...

碧波之心——心如碧波,静如止水 3万+

providers出现重复问题。

现在android studio的使用已经很普遍了,引用包也越来越方便,然后就出现了一些奇葩的问题,比如说provider重复问题。在引用compile ‘com.jph.takephoto:takephoto_library:4.0.3’ 这个类库时发现此类库里的注册文件中也包含provider文件,造成了重复。所以只能通过下面这种方式解决。 <provider ...

u013377714的专栏 962

自定义springboot starter

日常工作中有时有一些独立于业务之外的功能或模块,可能这个项目在用,另一个项目也要用,如果每次都重新集成的话就会很麻烦,这时我们只要把这些功能或模块封装成一个个starter的话,在使用的时候引入进去就很方便了。新建两个模块,命名规范: springboot自带的starter命名规范为spring-boot-starter-xxx, 自定义的starter命名规范为xxx-spring-boot-starter● xxx-spring-boot-autoconfigure:自动配置核心代码。

m0_73330311的博客 398
上一篇: 腾讯架构实践:SpringBoot+SpringCloud+Docker+Nginx+分布式
下一篇: 阿里巴巴开发手册“泰山”版1.4.0+终极版+灵魂十三问+阿里内部PPT
Java斗帝之路
博客等级 码龄7年 2392粉丝 687原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值