zoukankan      html  css  js  c++  java
  • 【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

  • 相关阅读:
    Code Forces 650 C Table Compression(并查集)
    Code Forces 645B Mischievous Mess Makers
    POJ 3735 Training little cats(矩阵快速幂)
    POJ 3233 Matrix Power Series(矩阵快速幂)
    PAT 1026 Table Tennis (30)
    ZOJ 3609 Modular Inverse
    Java实现 LeetCode 746 使用最小花费爬楼梯(递推)
    Java实现 LeetCode 745 前缀和后缀搜索(使用Hash代替字典树)
    Java实现 LeetCode 745 前缀和后缀搜索(使用Hash代替字典树)
    Java实现 LeetCode 745 前缀和后缀搜索(使用Hash代替字典树)
  • 原文地址:https://www.cnblogs.com/2YSP/p/10911166.html
Copyright © 2011-2022 走看看