• 【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

  • 相关阅读:
    96. Unique Binary Search Trees1和2
    576. Out of Boundary Paths
    686. Repeated String Match判断字符串重复几次可以包含另外一个
    650. 2 Keys Keyboard
    Penetration Test
    Penetration Test
    Penetration Test
    Penetration Test
    CISSP 考试经验分享
    2019-2020 ICPC Asia Hong Kong Regional Contest J—Junior Mathematician 数位dp
  • 原文地址:https://www.cnblogs.com/2YSP/p/10911166.html
Copyright © 2020-2023  润新知