参考:

https://blog.csdn.net/qq_39654841/article/details/134723185

https://blog.csdn.net/2301_78646673/article/details/134151020

https://www.jb51.net/program/3242215az.htm

可参考项目:

https://gitee.com/snjl/user-starter

为何要自定义starter

DRY (Don’t Repeat Yourself) 原则,通俗的说就是不重复造轮子,尽可能使用可重用的代码。我们可以把重复的代码提取出来,比如自定义一个库,然后在多个地方调用。对于相同的逻辑,在修改的时候应该只修改一个地方,而不是修改使用该相同逻辑的所有地方。尤其是使用微服务时,自定义starter是解决代码重复的关键方案。

starter命名规范

springboot 命名有两种规范:

  • spring-boot-starter-*:官方的命名规则,比如:spring-boot-starter-data-redis

  • *-spring-boot-starter:第三方项目的命名规则,比如:druid-spring-boot-starter

自定义一个starter

步骤

定义一个springboot starter分以下几步:

  1. 引入spring-boot-autoconfigure依赖

  2. 创建 配置文件XxxProperties:这个类的属性名对应着配置文件中的属性名。

  3. 创建自动配置类 AutoConfiguration:自动配置的一些逻辑,同时也要让XXXProperties 类生效。

  4. 将自动配置类放入自动配置文件中,不同版本对应的配置文件不同,按需选择。

    • springboot 2.7 之前自动配置文件为spring.factories ,配置内容的形式如下:

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
  • springboot 2.7到springboot 3.0,自动配置文件可以使用spring.factories,也可以使用META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports,推荐使用后者

  • springboot 3.0之后自动配置文件只能使用META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

实践

爱学习、爱锻炼鸡肉的人都会知道一些网站,然后通过网站各种学习知识、各种锻炼鸡肉。下面我们就做一个这样的栗子,在配置文件中配置好网站名称和链接,然后在另一个类中打来网站。

项目使用 springboot 3.2java 17

  1. 创建一个custom-starter 项目,并引入如下依赖:

<dependency>
   <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
​
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>

spring-boot-autoconfigure依赖是必须要引入的,spring-boot-configuration-processor的引入是为了在配置文件中使用属性时有提示。

  1. 创建属性配置类

@ConfigurationProperties(prefix = "movie.site")
public class MovieSiteProperties {
​
    /**
     * 网站名称
     */
    private String name;
    /** 网站地址 */
    private String url;
    //省去getter、setter方法
}

spring-boot-configuration-processor依赖引入之后,在属性上使用多行注释,在配置文件中使用属性时会有提示语。

  1. 创建自动配置类

创建自动配置类之前,先创建一个使用属性配置类的类

public class MovieSiteTemplate {
​
    private MovieSiteProperties movieSiteProperties;
​
    public MovieSiteTemplate(MovieSiteProperties movieSiteProperties) {
        this.movieSiteProperties = movieSiteProperties;
    }
​
​
    public void openSite(){
        System.out.println("打开网站:"+movieSiteProperties.getName()+",地址:"+movieSiteProperties.getUrl() +" 学习知识。");
    }
}

自动配置类:

@Configuration
@EnableConfigurationProperties(MovieSiteProperties.class)
public class MovieSiteAutoConfiguration {
​
    private  MovieSiteProperties movieSiteProperties;
​
    public MovieSiteAutoConfiguration(MovieSiteProperties movieSiteProperties) {
        this.movieSiteProperties = movieSiteProperties;
    }
​
    @Bean
    @ConditionalOnMissingBean(MovieSiteTemplate.class)
    public MovieSiteTemplate movieSiteTemplate(){
        return new MovieSiteTemplate(movieSiteProperties);
    }
}

在自动配置类中使用了条件注解 @ConditionalOnMissingBean,下一篇文件会介绍一下springboot有哪些条件注解,它们都有什么用。

  1. 创建自动配置文件 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports,引入配置类全限定名

  1. 使用Maven打包将custom-starter 打成jar包

mvn clean

  1. 在创建一个新项目springboot-practice,pom文件中引入自定义的starter 我这里是把 custom-starter 项目的artifactId改成了 movive-site-spring-boot-starter,不影响使用。

<dependency>
    <groupId>site.sunlong</groupId>
    <artifactId>movive-site-spring-boot-starter</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>
  1. springboot-practice项目的配置文件中配置MovieSiteProperties 类中的属性。

括号内就是MovieSiteProperties 类的属性注释,也就是上面说的提示语。

application.properties 配置文件内容,爱学习的人都知道的:

movie.site.name=91
movie.site.url=unknown
  1. 创建测试类进行测试

@SpringBootTest
class SpringbootPracticeApplicationTests {
​
    @Autowired
    private MovieSiteTemplate movieSiteTemplate;
​
    @Test
    void contextLoads() {
        movieSiteTemplate.openSite();
    }
}