一、什么是Starter?

在开发过程中我们就经常使用到各种starter,比如mybatis-spring-boot-starter,只需要进行简单的配置即可使用,就像一个插件非常方便。这也是SpringBoot非常重要的一个特性——自动化配置。

二、实现

2.1创建一个maven项目并配置pom.xml

命名规范: Spring官方的Starter命名格式一般是spring-boot-starter-{name},比如spring-boot-starter-web 。而非官方的,官方建议artifactId命名应该遵循 {name}-spring-boot-starter的格式,如example-spring-boot-starter。

pom文件

  1. <?xml version="1.0" encoding="UTF-8"?> 

  2. <project xmlns="http://maven.apache.org/POM/4.0.0" 

  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 

  4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 

  5. <modelVersion>4.0.0</modelVersion> 


  6. <groupId>cn.sp</groupId> 

  7. <artifactId>example-spring-boot-starter</artifactId> 

  8. <version>1.0-SNAPSHOT</version> 


  9. <properties> 

  10. <spring-boot.version>2.1.5.RELEASE</spring-boot.version> 

  11. </properties> 


  12. <dependencies> 

  13. <dependency> 

  14. <groupId>org.springframework.boot</groupId> 

  15. <artifactId>spring-boot-configuration-processor</artifactId> 

  16. <optional>true</optional> 

  17. </dependency> 


  18. <dependency> 

  19. <groupId>org.springframework.boot</groupId> 

  20. <artifactId>spring-boot-autoconfigure</artifactId> 

  21. </dependency> 

  22. </dependencies> 



  23. <dependencyManagement> 

  24. <dependencies> 

  25. <dependency> 

  26. <!-- Import dependency management from Spring Boot --> 

  27. <groupId>org.springframework.boot</groupId> 

  28. <artifactId>spring-boot-dependencies</artifactId> 

  29. <version>${spring-boot.version}</version> 

  30. <type>pom</type> 

  31. <scope>import</scope> 

  32. </dependency> 

  33. </dependencies> 

  34. </dependencyManagement> 


  35. </project> 

spring-boot-configuration-processor 的作用是编译时生成 spring-configuration-metadata.json ,此文件主要给IDE使用,ctlr+鼠标左键点击配置文件(如application.properties)上相关配置属性,即可跳转到配置此属性的类中。

我们要实现的一个小功能是读取配置文件上cn.sp.config的字符串,然后按照给定的分隔符进行分割。

2.2编写配置文件读取类

@ConfigurationProperties(prefix = "cn.sp")
public class StarterServiceProperties { private String config; public String getConfig() {
return config;
} public void setConfig(String config) {
this.config = config;
}
}

2.3编写Service

public class StarterService {

    private String config;

    public StarterService(String config){
this.config = config;
} public String[] split(String separatorChar){ return this.config.split(separatorChar);
}
}

2.4编写自动配置类(重点)

  1. package cn.sp.autoconfigure; 


  2. import org.springframework.beans.factory.annotation.Autowired; 

  3. import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; 

  4. import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 

  5. import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 

  6. import org.springframework.boot.context.properties.EnableConfigurationProperties; 

  7. import org.springframework.context.annotation.Bean; 

  8. import org.springframework.context.annotation.Configuration; 


  9. /** 

  10. * Created by 2YSP on 2019/5/22. 

  11. */ 

  12. @Configuration 

  13. @ConditionalOnClass(StarterService.class) 

  14. //@ConditionalOnProperty(prefix = "cn.sp",value = "enable",matchIfMissing = true) 

  15. @EnableConfigurationProperties(StarterServiceProperties.class) 

  16. public class StarterAutoConfigure { 


  17. @Autowired 

  18. private StarterServiceProperties properties; 


  19. @Bean 

  20. @ConditionalOnMissingBean 

  21. @ConditionalOnProperty(prefix = "cn.sp",value = "enabled",havingValue = "true") 

  22. StarterService starterService(){ 

  23. return new StarterService(properties.getConfig()); 

  24. } 


  25. } 


说下这几个注解的作用:

  1. @ConditionalOnClass:当classpath下发现该类的情况下进行自动配置。
  2. @EnableConfigurationProperties:使使用 @ConfigurationProperties 注解的类生效。具体可以参考https://www.jianshu.com/p/7f54da1cb2eb
  3. @ConditionalOnMissingBean:当Spring上下文中不存在该Bean时生效。
  4. @ConditionalOnProperty(prefix = "cn.sp",value = "enabled",havingValue = "true"),当配置文件中cn.sp.enabled=true时有效。

下面列举SpringBoot中的所有@Conditional注解及作用

@ConditionalOnBean:当容器中有指定的Bean的条件下
@ConditionalOnClass:当类路径下有指定的类的条件下
@ConditionalOnExpression:基于SpEL表达式作为判断条件
@ConditionalOnJava:基于JVM版本作为判断条件
@ConditionalOnJndi:在JNDI存在的条件下查找指定的位置
@ConditionalOnMissingBean:当容器中没有指定Bean的情况下
@ConditionalOnMissingClass:当类路径下没有指定的类的条件下
@ConditionalOnNotWebApplication:当前项目不是Web项目的条件下
@ConditionalOnProperty:指定的属性是否有指定的值
@ConditionalOnResource:类路径下是否有指定的资源
@ConditionalOnSingleCandidate:当指定的Bean在容器中只有一个,或者在有多个Bean的情况下,用来指定首选的Bean
@ConditionalOnWebApplication:当前项目是Web项目的条件下

2.5创建spring.factories

在 resources/META-INF/ 文件夹下创建spring.factories文件,内容如下:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=cn.sp.autoconfigure.StarterAutoConfigure

右边的就是自动配置类的类路径,注意单词别打错了,我就是META-INF打成了MATA-INF害我折腾了半天。

三、测试

  1. 执行mvn install命令打包到本地
  2. 在另外一个项目添加依赖
<dependency>
<groupId>cn.sp</groupId>
<artifactId>example-spring-boot-starter</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>

然后可以看到jar包的结构图如下:

3. 在application.properties文件添加如下内容

cn.sp.enabled=true
cn.sp.config=fdafdf,ss1,DSDS,DDD
  1. 编写测试类并启动
@RunWith(SpringRunner.class)
@SpringBootTest
public class MySpringbootApplicationTests { @Autowired
StarterService starterService; @Test
public void contextLoads() {
String[] strings = starterService.split(",");
for (int i = 0; i < strings.length; i++) {
System.out.println(strings[i]);
}
} }
  1. 运行结果如下则表示成功。

2019-05-23 10:41:49.219 [main] INFO cn.sp.MySpringbootApplicationTests - Started MySpringbootApplicationTests in 10.977 seconds (JVM running for 13.035)
fdafdf
ss1
DSDS
DDD

2019-05-23 10:41:52.411 [Thread-4] INFO o.s.w.c.s.GenericWebApplicationContext - Closing org.springframework.web.context.support.GenericWebApplicationContext@51f49060: startup date [Thu May 23 10:41:38 CST 2019]; root of context hierarchy

四、原理

1.在应用程序启动过程中,Spring Boot使用SpringFactoriesLoader类加载器查找org.springframework.boot.autoconfigure.EnableAutoConfiguration关键字对应的Java配置文件。Spring Boot会遍历在各个jar包中META-INF目录下的spring.factories文件,构建成一个配置文件链表。
2.根据spring.factories配置加载AutoConfigure类
3.根据 @Conditional注解的条件,进行自动配置并将Bean注入Spring Context中。
注意: Spring Boot的starter在编译时不需要依赖Spring Boot的库。
代码地址:https://github.com/2YSP/example-spring-boot-starter
参考:
https://juejin.im/entry/58d37630570c350058c2c15c
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-developing-auto-configuration.html

【SpringBoot】编写一个自己的Starter的更多相关文章

  1. SpringBoot编写自定义的starter 专题

    What’s in a name All official starters follow a similar naming pattern; spring-boot-starter-*, where ...

  2. 编写一个可复用的SpringBoot应用运维脚本

    前提 作为Java开发者,很多场景下会使用SpringBoot开发Web应用,目前微服务主流SpringCloud全家桶也是基于SpringBoot搭建的.SpringBoot应用部署到服务器上,需要 ...

  3. JAVA WEB快速入门之从编写一个基于SpringBoot+Mybatis快速创建的REST API项目了解SpringBoot、SpringMVC REST API、Mybatis等相关知识

    JAVA WEB快速入门系列之前的相关文章如下:(文章全部本人[梦在旅途原创],文中内容可能部份图片.代码参照网上资源) 第一篇:JAVA WEB快速入门之环境搭建 第二篇:JAVA WEB快速入门之 ...

  4. 从零开始开发一个Spring Boot Starter

    一.Spring Boot Starter简介 Starter是Spring Boot中的一个非常重要的概念,Starter相当于模块,它能将模块所需的依赖整合起来并对模块内的Bean根据环境( 条件 ...

  5. SpringBoot内置的各种Starter是怎样构建的?--SpringBoot源码(六)

    注:该源码分析对应SpringBoot版本为2.1.0.RELEASE 1 温故而知新 本篇接 外部配置属性值是如何被绑定到XxxProperties类属性上的?--SpringBoot源码(五) 温 ...

  6. 基于SpringBoot开发一个Restful服务,实现增删改查功能

    前言 在去年的时候,在各种渠道中略微的了解了SpringBoot,在开发web项目的时候是如何的方便.快捷.但是当时并没有认真的去学习下,毕竟感觉自己在Struts和SpringMVC都用得不太熟练. ...

  7. 开发一个Spring Boot Starter!

    在上一篇文章中,我们已经了解了一个starter实现自动配置的基本流程,在这一小结我们将复现上一过程,实现一个自定义的starter. 先来分析starter的需求: 在项目中添加自定义的starte ...

  8. springboot搭建一个简单的websocket的实时推送应用

    说一下实用springboot搭建一个简单的websocket 的实时推送应用 websocket是什么 WebSocket是一种在单个TCP连接上进行全双工通信的协议 我们以前用的http协议只能单 ...

  9. 【SpingBoot】 测试如何使用SpringBoot搭建一个简单后台1

    很久没写博客了,最近接到一个组内的测试开发任务是做一个使用SpringBoot 开发一个后台程序(还未完成),特写感想记录一下 1. 为什么选择SpringBoot ? 首先是目前很多公司的后台还是J ...

随机推荐

  1. uboot 从sd卡加载文件并烧写到nand flash

    uboot下可以从用tftp和nfs加载文件. 但是现在有个开发板配套uboot网络功能出现异常,执行ping命令就会导致开发板重启,只能选择先从sd卡加载文件 启动开发板,任意键进入uboot,然后 ...

  2. 用ant编译打包时 警告:编码 GBK 的不可映射字符

    原因,参考http://zhidao.baidu.com/question/26901568.html 添加如下的红色一行后编译通过<target name="compile" ...

  3. LINQ to Entities 不识别方法"System.String ToString()",因此该方法无法转换为存储表达式 的解决方法

    一.案例1,及解决方案: "LINQ to Entities 不识别方法"System.String ToString()",因此该方法无法转换为存储表达式." ...

  4. ubuntu14开发环境配置

    1 配置JDK1.8 jdk工具从官网下载,我下载到了~/tool目录下,首先进入用户的bash配置目录,打开配置文件: cd ~ vi .bashrc 编辑.bashrc文件,在适当位置或者文件最后 ...

  5. poj1475 Pushing Boxes[双重BFS(毒瘤搜索题)]

    地址. 很重要的搜索题.★★★ 吐槽:算是写过的一道码量比较大的搜索题了,细节多,还比较毒瘤.虽然是一遍AC的,其实我提前偷了大数据,但是思路还是想了好长时间,照理说想了半小时出不来,我就会翻题解,但 ...

  6. CodeForces - 434D Nanami's Power Plant

    Codeforces - 434D 题目大意: 给定一个长为n的序列,序列中的第i为上的值\(x_i\),序列第i位上的值\(x_i\in[l_i,r_i]\),价值为\(f_i(x_i)\),其中\ ...

  7. 解决CentOS 7安装zabbix 3.0 无法启动zabbix-server的问题[segfault at 18 ip 00007f78842b4bd0 sp 00007fff1995a818 error 4 in libpthread-2.17.so[7f78842ab000+16000]]

    解决CentOS 7安装zabbix 3.0 无法启动zabbix-server的问题 [root@localhost sbin]# service zabbix-server start Redir ...

  8. 功能测试工具Selenium IDE

    Selenium IDE:一个专门用于Firefox浏览器的插件,能够录制回放用户在Firefox中的行为,并把所记录的Selenese (Selenium Commands)转化为HTML/Java ...

  9. C++ 右值引用与移动操作

    右值引用和移动操作是C++11提出的新概念,通过这些操作,可以降低拷贝操作带来的消耗.先来简单介绍一下左值和右值. 左值一般指的是一个对象,或者说是一个持久的值,例如赋值的返回值.下标操作.解引用以及 ...

  10. c程序十六进制字符串转换为整数与反转

    字符串转整数使用sscanf ; char *buf = "1d5ce"; sscanf (buf, "%x", &value); printf (&q ...