一、引言

什么是Spring Boot Starter呢?我们直接来看看官网是怎么介绍的吧。

Starters are a set of convenient dependency descriptors that you can include in your application. You get a one-stop shop for all the Spring and related technologies that you need without having to hunt through sample code and copy-paste loads of dependency descriptors. For example, if you want to get started using Spring and JPA for database access, include the spring-boot-starter-data-jpa dependency in your project.

我们以上述官网的例子来进行说明比如说我们需要在Spring 中适应JPA来操作数据库。在没有springBoot-starter之前,我们需要引入jpa的步骤

  • 通过maven 引入 jdbc 的依赖、以及 jpa 相关的各种依赖

  • 编写jpa相关的配置文件

  • 网上各种查询找资料进行调试,调试的过程对于新手可能会有点奔溃会遇到各种奇奇怪怪的问题,jar包冲突啊,这个jar包下载不下来,缺少某个jar包。

  • 终于在经历千辛万苦,哼次哼次的解决各种问题之后终于把项目跑起来了,然后把这次整合jpa遇到的问题,以及整合的步骤都一一的详细记录下来。方便下次在需要整合jpa的时候直接copy就好了。我们以前在没有starter之前是不是都是这么玩的。这样的缺点是不是也非常显著,比如过程复杂、需要不停的粘贴复制(不过这是程序员经常干的事情了,也不在乎多一两次了)、整合其它组件到自己的项目变的困难,效率低下。

二、SpringBoot Starter 的出现

我们可以看下SpringBoot 现在都为我们提供有哪些starter,这截图了部分starter,更多的请点击https://github.com/spring-projects/spring-boot/tree/master/spring-boot-project/spring-boot-starters

  • starter的实现:虽然我们每个组件的starter实现各有差异,但是它们基本上都会使用到两个相同的内容:ConfigurationProperties和AutoConfiguration
  • 因为SpringBoot提倡“「约定大于配置」”这一理念,所以我们使用ConfigurationProperties来保存我们的配置,并且这些配置都可以有一个默认值,即在我们没有主动覆写原始配置的情况下,默认值就会生效。
  • 除此之外,starter的ConfigurationProperties还使得所有的配置属性被聚集到一个文件中(一般在resources目录下的application.properties),这样我们就告别了Spring项目中XML地狱。starter的出现帮把我们把各种复杂的配置都封装起来了,让我们真正的可以达到了开箱即用。不仅降低了我们使用它的门槛,并且还大大提高了我们的开发效率。
  • 整体逻辑

三、实现自己的 SpringBoot Starter

  1. 命名规范
    在maven中,groupId代表着姓氏,artifactId代表着名字。Spring Boot也是有一个命名的建议的。所以名字是不能够随随便便取得,可以按照官方的建议来取
What’s in a nameAll official starters follow a similar naming pattern; spring-boot-starter-*, where * isa particular type of application. This naming structure is intended to help when you need to find a starter. The Maven integration in many IDEs lets you search dependencies by name. For example, with the appropriate Eclipse or STS plugin installed, you can press ctrl-space in the POM editor and type “spring-boot-starter” for a complete list.As explained in the “Creating Your Own Starter” section, thirdparty starters should not start with spring-boot, as it is reserved for official Spring Boot artifacts.Rather, a third-party starter typically starts with the name of the project. For example, a third-party starter project called thirdpartyproject would typically be named thirdpartyproject-spring-boot-starter.

大概意思是:

  • 官方的 starter 的命名格式为 spring-boot-starter-{xxxx}比如spring-boot-starter-activemq
  • 第三方我们自己的命名格式为{xxxx}-spring-boot-starter。比如mybatis-spring-boot-starter。
  • 如果我们忽略这种约定,是不是会显得我们写的东西不够“专业“。
  1. 自定义一个 Starter
    下面我们就来实现一个自定义的发送短信的 starter,命名为sms-spring-boot-starter。
  • 编写配置文件匹配类

发短信我们需要配置一些账号信息,不同的短信供应商,账户信息是不一样的,所以我们需要定义一个XXXXProperties 来自动装配这些账户信息。下面我们就以腾讯云和阿里云两家供应商为例;

//配置前缀,区别各个组件的参数
@ConfigurationProperties(prefix = "sms")
@Data
public class SmsProperties {private SmsMessage aliyun = new SmsMessage();private SmsMessage tencent = new SmsMessage();@Datapublic static class SmsMessage{/*** 用户名*/private String userName;/*** 密码*/private String passWord;/*** 秘钥*/private String sign;/****/private String url;@Overridepublic String toString() {return "SmsMessage{" +"userName='" + userName + '\'' +", passWord='" + passWord + '\'' +", sign='" + sign + '\'' +", url='" + url + '\'' +'}';}}
}
  • 编写自动配置类
@EnableConfigurationProperties(value = SmsProperties.class)
@Configuration
public class SmsAutoConfiguration  {/***  阿里云发送短信的实现类* @param smsProperties* @return*/@Beanpublic AliyunSmsSenderImpl aliYunSmsSender(SmsProperties smsProperties){return new AliyunSmsSenderImpl(smsProperties.getAliyun());}/*** 腾讯云发送短信的实现类* @param smsProperties* @return*/@Beanpublic TencentSmsSenderImpl tencentSmsSender(SmsProperties smsProperties){return new TencentSmsSenderImpl(smsProperties.getTencent());}
}
  • 编写两个业务类便于测试
@ConditionalOnMissingBean({SmsMessage.class})
public class AliyunSmsSenderImpl implements SmsSender{private final SmsMessage smsMessage;public AliyunSmsSenderImpl(SmsMessage smsProperties) {this.smsMessage = smsProperties;}@Overridepublic boolean send(String message) {System.out.println(smsMessage.toString()+"开始发送短信==》短信内容:"+message);return true;}
}
  • 让 starter 生效

starter集成应用有两种方式(被动生效和主动生效):

  • 被动生效:通过SpringBoot的SPI的机制来去加载我们的 starter
    我们需要在META-INF下新建一个spring.factories文件key为org.springframework.boot.autoconfigure.EnableAutoConfiguration, value是我们的SmsAutoConfiguration 全限定名(「记得去除前后的空格,否则会不生效」)。
  • 主动生效:前提是先注销spring.factories
    主动生效在starter组件集成到我们的Spring Boot应用时需要主动声明启用该starter才生效,通过自定义一个@Enable注解然后在把自动配置类通过Import注解引入进来
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({SmsAutoConfiguration.class})
public @interface EnableSms {}

使用的时候需要在启动类上面开启这个注解即可。

至此,我们的自定义starter已经写好了,接下来就是打包生成starter.jar。下面是工程完整结构:

注意,不是传统的可运行jar项目,所以没有主入口

  • pom.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.5.3</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.cristiano</groupId><artifactId>sms-spring-boot-starter</artifactId><version>0.0.1</version><name>sms-spring-boot-starter</name><description>sms-spring-boot-starter</description><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><!--安装到仓库后,引用时不出现 BOOT-INF文件夹(会导致找不到相关类)--><configuration><skip>true</skip></configuration></plugin></plugins></build></project>

重点注意:如果maven没有这么配置,那么打包成jar的时候,会出现BOOT-INF文件夹,导致使用模块的时候,找不到类,详细参考这篇文章

 <plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><!--安装到仓库后,引用时不出现 BOOT-INF文件夹(会导致找不到相关类)--><configuration><skip>true</skip></configuration></plugin></plugins>


Lifecycle下install就可以将模块引用到本地仓库了

四、测试Starter

  • 引用
        <dependency><groupId>com.cristiano</groupId><artifactId>sms-spring-boot-starter</artifactId><version>0.0.1</version></dependency>
  • 启用
@SpringBootApplication
@EnableSms
public class TeststarterApplication {public static void main(String[] args) {SpringApplication.run(TeststarterApplication.class, args);}
}
  • 配置(有提示)
  • 测试

    至此就结束了么?其实上面的例子加不加@EnableSms,都能正常打印信息,因为我们在Starter的spring.factories中已经配置了自动配置类,属于被动加载。

五、插拔式starter(基于主动依赖)

  1. 在SmsAutoConfiguration的原基础上,加上以下注解后,重新install
@EnableConfigurationProperties(value = SmsProperties.class)
@Configuration
public class SmsAutoConfiguration  {/***  阿里云发送短信的实现类* @param smsProperties* @return*/@Bean//表示在EnableSms注解存在的情况下,该bean才会被注册@ConditionalOnBean(annotation = EnableSms.class)public AliyunSmsSenderImpl aliYunSmsSender(SmsProperties smsProperties){return new AliyunSmsSenderImpl(smsProperties.getAliyun());}/*** 腾讯云发送短信的实现类* @param smsProperties* @return*/@Beanpublic TencentSmsSenderImpl tencentSmsSender(SmsProperties smsProperties){return new TencentSmsSenderImpl(smsProperties.getTencent());}
}
  • EnableSms
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({SmsAutoConfiguration.class})
public @interface EnableSms {}
  • 主配置类
//不使用@EnableSms
@SpringBootApplication
public class TeststarterApplication {public static void main(String[] args) {SpringApplication.run(TeststarterApplication.class, args);}
}

可以看到报错,原因是AliyunSmsSenderImpl 没有注册到bean中,所以使用条件注解可以实现starter的插拔式应用

正式使用

@EnableSms
@SpringBootApplication
public class TeststarterApplication {public static void main(String[] args) {SpringApplication.run(TeststarterApplication.class, args);}
}
 //注入AliyunSmsSenderImpl@AutowiredAliyunSmsSenderImpl aliyunSmsSender;public void test(){aliyunSmsSender.send("from aliyun");}

配置

sms:aliyun:pass-word: aauser-name: aaurl: www.aliyun.comsign: alibaba

参考文章
参考文章

自定义 Spring Boot Starter相关推荐

  1. 快速开发一个自定义 Spring Boot Starter ,希望你也会

    来源:http://t.cn/Ai9li9fC 众所周知,Spring Boot由众多Starter组成,随着版本的推移Starter家族成员也与日俱增.在传统Maven项目中通常将一些层.组件拆分为 ...

  2. 自定义依赖注解无效_最详细的自定义Spring Boot Starter开发教程

    1.前言 随着Spring的日渐臃肿,为了简化配置.开箱即用.快速集成,Spring Boot 横空出世.目前已经成为 Java 目前最火热的框架了.平常我们用Spring Boot开发web应用.S ...

  3. Spring Boot - 手把手教小师妹自定义Spring Boot Starter

    文章目录 Pre 自定义starter的套路 步骤 命名规范 官方命名空间 自定义命名空间 实战 创建一个父maven项目:springboot_custome_starter 创建 两个Module ...

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

    点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 写在前面 我们每次构建一个 Spring 应用程序时,我 ...

  5. 一个项目有两个pom_实现一个Spring Boot Starter超简单,读 Starter 源码也不在话下...

    Spring Boot 对比 Spring MVC 最大的优点就是使用简单,约定大于配置.不会像之前用 Spring MVC 的时候,时不时被 xml 配置文件搞的晕头转向,冷不防还因为 xml 配置 ...

  6. 《SpringCloud超级入门》Spring Boot Starter的介绍及使用《七》

    目录 Spring Boot Starter项目创建 自动创建客户端 使用 Starter 使用注解开启 Starter 自动构建 使用配置开启 Starter 自动构建 配置 Starter 内容提 ...

  7. 实现一个 Spring Boot Starter 原来如此简单,读 Starter 源码也不在话下

    我是风筝,公众号「古时的风筝」,一个在程序圈混迹多年,主业 Java,另外 Python.React 也玩儿的 6 的斜杠开发者.现已转行程序员鼓励师 Spring Cloud 系列文章已经完成,可以 ...

  8. 自定义Spring Boot Starters

    传统的做法 在没有starter之前,假如我想要在Spring中使用jpa,那我可能需要做以下操作: 在Maven中引入使用的数据库的依赖(即JDBC的jar) 引入jpa的依赖 在xxx.xml中配 ...

  9. 一个简易上手的短信服务Spring Boot Starter,连傻瓜都会!

    作 者:jackieonway 来 源:jianshu.com/u/36510c75d37c 短信服务在用户注册.登录.找回密码等相关操作中,可以让用户使用更加便捷,越来越多的公司都采用短信验证的方式 ...

最新文章

  1. 关于librtmp接收数据(接收网络电视的数据流)
  2. 【转】WebSocket初探
  3. postgresql 远程用户_构建Python pandas基于SSH远程MySQL和PostgreSQL的数据分析
  4. 优秀!本科生发表Nature论文,直博美国顶尖名校
  5. 浏览器皮肤_和平精英返场皮肤投票时间是什么时候?投票地址入口介绍-手游资讯...
  6. 微信公众号之生成带参数的二维码
  7. vagrant虚拟机网络设置
  8. 【python】opencv、PIL、gdal读取tif高分遥感影像比较
  9. 经验| 张家口交通综合运行协调与应急指挥中心建设
  10. 注册美国iTunes账号步骤(跳过绑定银行卡)
  11. Html页面点击下载文件
  12. Windows10没有画图软件的解决方式
  13. 【毕业设计】stm32智能车牌识别系统 - 单片机 嵌入式
  14. 要开始写日志了(Live Witer)
  15. 菜鸟程序员成长之路(七)——2020年,你奋斗了吗?
  16. python编程100例海绵宝宝-Python_Turtle库画一只派大星
  17. oracle12c用plsql连不上,PLSQL连接oracle12c
  18. javascript+css实现走马灯图片轮播器
  19. 【测试】工艺路线展开Function
  20. 入门 redux 和 @connect 装饰器

热门文章

  1. python-map函数
  2. 借助JVM生日的时机,说说关于JVM你所不知道的那些事
  3. bootstrap 之下拉多选
  4. Java中String字符串toString()、String.valueOf()、String强转、+ 的区别
  5. 1313 质因数分解 2012年NOIP全国联赛普及组
  6. machine learning (5)---learning rate
  7. 根据先序和中序序列重建二叉树
  8. matlab 中imagesc的用法
  9. 在java 里kv 是什么_consul kv使用介绍
  10. [云炬创业学笔记]第三章商业创意的发掘与评估测试4