【SpringBoot】编写一个自己的Starter

一、什么是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.  
  7. <groupId>cn.sp</groupId> 
  8. <artifactId>example-spring-boot-starter</artifactId> 
  9. <version>1.0-SNAPSHOT</version> 
  10.  
  11. <properties> 
  12. <spring-boot.version>2.1.5.RELEASE</spring-boot.version> 
  13. </properties> 
  14.  
  15. <dependencies> 
  16. <dependency> 
  17. <groupId>org.springframework.boot</groupId> 
  18. <artifactId>spring-boot-configuration-processor</artifactId> 
  19. <optional>true</optional> 
  20. </dependency> 
  21.  
  22. <dependency> 
  23. <groupId>org.springframework.boot</groupId> 
  24. <artifactId>spring-boot-autoconfigure</artifactId> 
  25. </dependency> 
  26. </dependencies> 
  27.  
  28.  
  29. <dependencyManagement> 
  30. <dependencies> 
  31. <dependency> 
  32. <!-- Import dependency management from Spring Boot --> 
  33. <groupId>org.springframework.boot</groupId> 
  34. <artifactId>spring-boot-dependencies</artifactId> 
  35. <version>${spring-boot.version}</version> 
  36. <type>pom</type> 
  37. <scope>import</scope> 
  38. </dependency> 
  39. </dependencies> 
  40. </dependencyManagement> 
  41.  
  42. </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.  
  3. import org.springframework.beans.factory.annotation.Autowired; 
  4. import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; 
  5. import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 
  6. import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 
  7. import org.springframework.boot.context.properties.EnableConfigurationProperties; 
  8. import org.springframework.context.annotation.Bean; 
  9. import org.springframework.context.annotation.Configuration; 
  10.  
  11. /** 
  12. * Created by 2YSP on 2019/5/22. 
  13. */ 
  14. @Configuration 
  15. @ConditionalOnClass(StarterService.class) 
  16. //@ConditionalOnProperty(prefix = "cn.sp",value = "enable",matchIfMissing = true) 
  17. @EnableConfigurationProperties(StarterServiceProperties.class) 
  18. public class StarterAutoConfigure
  19.  
  20. @Autowired 
  21. private StarterServiceProperties properties; 
  22.  
  23. @Bean 
  24. @ConditionalOnMissingBean 
  25. @ConditionalOnProperty(prefix = "cn.sp",value = "enabled",havingValue = "true"
  26. StarterService starterService()
  27. return new StarterService(properties.getConfig()); 
  28.  
  29.  

说下这几个注解的作用:

  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包的结构图如下:
enter description here
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

posted @ 2019-05-23 12:13  烟味i  阅读(1141)  评论(1编辑  收藏