Spring Boot已经内置了127个场景启动器,基本上满足大部分的使用场景,但是有时候也会存在需要自定义starter的场景,如何自定义一个starter呢?其实也很简单,这里简单介绍如何自定义的关键步骤。

  • 创建自定义starter工程demo-spring-boot-starter
  • 创建测试工程demo-web,引入自定义starter验证。

    创建starter工程

    首先创建一个自定义starter工程,除了spring官方的starter之外,第三方的starter一般命名规则遵循*-spring-boot-starter的原则,引入相应依赖,此处只引入满足条件最小依赖,也可以根据实际场景引入,注意maven的依赖传递原则,不要和外部的冲突,解决好依赖关系。

工程名称:demo-spring-boot-starter

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  4. <modelVersion>4.0.0</modelVersion>
  5. <parent>
  6. <groupId>org.springframework.boot</groupId>
  7. <artifactId>spring-boot-starter-parent</artifactId>
  8. <version>2.6.0</version>
  9. <relativePath/> <!-- lookup parent from repository -->
  10. </parent>
  11. <groupId>com.starsray</groupId>
  12. <artifactId>demo-spring-boot-starter</artifactId>
  13. <version>0.0.1-SNAPSHOT</version>
  14. <name>demo-spring-boot-starter</name>
  15. <description>demo-spring-boot-starter</description>
  16. <properties>
  17. <java.version>1.8</java.version>
  18. </properties>
  19. <dependencies>
  20. <dependency>
  21. <groupId>org.springframework.boot</groupId>
  22. <artifactId>spring-boot-starter</artifactId>
  23. </dependency>
  24. </dependencies>
  25. </project>

创建自动配置类

spring boot中starter在工程启动时是否被加载,需要创建一个类来标明,一般来说只要命名是xxxAutoConfiguration,那就表明这是一个自动配置类。

一般一个自动配置类里面都会伴随着类似xxxProperties的配置文件类作为参数被加载,通过注解@EnableConfigurationProperties({A.class,B.class,...})来开启绑定,是否满足加载条件可以使用SpringBoot提供的@Conditionxxx系列注解来按需加载,这些类里面的属性一般都和工程配置文件的application.yml直接绑定,命名语法支持松散绑定。

  1. package com.starsray.starter;
  2. import com.starsray.starter.config.DemoConfig;
  3. import org.springframework.boot.ApplicationArguments;
  4. import org.springframework.boot.ApplicationRunner;
  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. import org.springframework.stereotype.Component;
  10. import javax.annotation.PostConstruct;
  11. import javax.annotation.Resource;
  12. /**
  13. * 演示自动配置
  14. *
  15. * @author starsray
  16. * @date 2021/11/20
  17. */
  18. @Configuration
  19. @EnableConfigurationProperties(DemoConfig.class)
  20. public class DemoAutoConfiguration {
  21. @Resource
  22. private DemoConfig demoConfig;
  23. @PostConstruct
  24. public void run() {
  25. System.out.printf("demo starter ---> %s%n", demoConfig.getName());
  26. }
  27. }

配置类DemoConfig

  1. package com.starsray.starter.config;
  2. import org.springframework.boot.context.properties.ConfigurationProperties;
  3. import org.springframework.context.annotation.Configuration;
  4. /**
  5. * 演示配置
  6. *
  7. * @author starsray
  8. * @date 2021/11/20
  9. */
  10. @Configuration
  11. @ConfigurationProperties(prefix = "demo")
  12. public class DemoConfig {
  13. private String name;
  14. public String getName() {
  15. return name;
  16. }
  17. public void setName(String name) {
  18. this.name = name;
  19. }
  20. }

配置加载信息

接下来最关键的一步,starter启动是否能被Spring Boot加载到,就要做此项配置。在resources目录下创建META-INF文件夹,创建spring.factories文件,内容如下:

  1. org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  2. com.starsray.starter.DemoAutoConfiguration

这句话是告诉spring boot在启动时要加载这个组件的位置。
工程启动过程中,Spring Boot会扫描classpath下META-INF文件夹中spring.factories文件的配置项,加载对应的starter。

创建测试工程

工程名称:demo-web


pom引入自定义starter

  1. <!--引入自定义starter-->
  2. <dependency>
  3. <groupId>com.starsray</groupId>
  4. <artifactId>demo-spring-boot-starter</artifactId>
  5. <version>0.0.1-SNAPSHOT</version>
  6. </dependency>

添加配置,测试配置项是否生效,在application.yml中添加配置。

  1. demo:
  2. name: demo config

启动工程

  1. /opt/develop/jdk1.8.0_301/bin/java -XX:TieredStopAtLevel=1 -noverify -Dspring.output.ansi.enabled=always -javaagent:/opt/apps/com.jetbrains.intellij-idea-ultimate/files/lib/idea_rt.jar=46683:/opt/apps/com.jetbrains.intellij-idea-ultimate/files/bin -Dcom.sun.management.jmxremote -Dspring.jmx.enabled=true -Dspring.liveBeansView.mbeanDomain -Dspring.application.admin.enabled=true -Dfile.encoding=UTF-8 -classpath /opt/develop/jdk1.8.0_301/jre/lib/charsets.jar:/opt/develop/jdk1.8.0_301/jre/lib/deploy.jar:/opt/develop/jdk1.8.0_301/jre/lib/ext/cldrdata.jar:/opt/develop/jdk1.8.0_301/jre/lib/ext/dnsns.jar:/opt/develop/jdk1.8.0_301/jre/lib/ext/jaccess.jar:/opt/develop/jdk1.8.0_301/jre/lib/ext/jfxrt.jar:/opt/develop/jdk1.8.0_301/jre/lib/ext/localedata.jar:/opt/develop/jdk1.8.0_301/jre/lib/ext/nashorn.jar:/opt/develop/jdk1.8.0_301/jre/lib/ext/sunec.jar:/opt/develop/jdk1.8.0_301/jre/lib/ext/sunjce_provider.jar:/opt/develop/jdk1.8.0_301/jre/lib/ext/sunpkcs11.jar:/opt/develop/jdk1.8.0_301/jre/lib/ext/zipfs.jar:/opt/develop/jdk1.8.0_301/jre/lib/javaws.jar:/opt/develop/jdk1.8.0_301/jre/lib/jce.jar:/opt/develop/jdk1.8.0_301/jre/lib/jfr.jar:/opt/develop/jdk1.8.0_301/jre/lib/jfxswt.jar:/opt/develop/jdk1.8.0_301/jre/lib/jsse.jar:/opt/develop/jdk1.8.0_301/jre/lib/management-agent.jar:/opt/develop/jdk1.8.0_301/jre/lib/plugin.jar:/opt/develop/jdk1.8.0_301/jre/lib/resources.jar:/opt/develop/jdk1.8.0_301/jre/lib/rt.jar:/home/starsray/IdeaProjects/custom-starter/demo-web/target/classes:/home/starsray/.m2/repository/org/springframework/boot/spring-boot-starter-web/2.6.0/spring-boot-starter-web-2.6.0.jar:/home/starsray/.m2/repository/org/springframework/boot/spring-boot-starter/2.6.0/spring-boot-starter-2.6.0.jar:/home/starsray/.m2/repository/org/springframework/boot/spring-boot/2.6.0/spring-boot-2.6.0.jar:/home/starsray/.m2/repository/org/springframework/boot/spring-boot-autoconfigure/2.6.0/spring-boot-autoconfigure-2.6.0.jar:/home/starsray/.m2/repository/org/springframework/boot/spring-boot-starter-logging/2.6.0/spring-boot-starter-logging-2.6.0.jar:/home/starsray/.m2/repository/ch/qos/logback/logback-classic/1.2.7/logback-classic-1.2.7.jar:/home/starsray/.m2/repository/ch/qos/logback/logback-core/1.2.7/logback-core-1.2.7.jar:/home/starsray/.m2/repository/org/slf4j/slf4j-api/1.7.32/slf4j-api-1.7.32.jar:/home/starsray/.m2/repository/org/apache/logging/log4j/log4j-to-slf4j/2.14.1/log4j-to-slf4j-2.14.1.jar:/home/starsray/.m2/repository/org/apache/logging/log4j/log4j-api/2.14.1/log4j-api-2.14.1.jar:/home/starsray/.m2/repository/org/slf4j/jul-to-slf4j/1.7.32/jul-to-slf4j-1.7.32.jar:/home/starsray/.m2/repository/jakarta/annotation/jakarta.annotation-api/1.3.5/jakarta.annotation-api-1.3.5.jar:/home/starsray/.m2/repository/org/springframework/spring-core/5.3.13/spring-core-5.3.13.jar:/home/starsray/.m2/repository/org/springframework/spring-jcl/5.3.13/spring-jcl-5.3.13.jar:/home/starsray/.m2/repository/org/yaml/snakeyaml/1.29/snakeyaml-1.29.jar:/home/starsray/.m2/repository/org/springframework/boot/spring-boot-starter-json/2.6.0/spring-boot-starter-json-2.6.0.jar:/home/starsray/.m2/repository/com/fasterxml/jackson/core/jackson-databind/2.13.0/jackson-databind-2.13.0.jar:/home/starsray/.m2/repository/com/fasterxml/jackson/core/jackson-annotations/2.13.0/jackson-annotations-2.13.0.jar:/home/starsray/.m2/repository/com/fasterxml/jackson/core/jackson-core/2.13.0/jackson-core-2.13.0.jar:/home/starsray/.m2/repository/com/fasterxml/jackson/datatype/jackson-datatype-jdk8/2.13.0/jackson-datatype-jdk8-2.13.0.jar:/home/starsray/.m2/repository/com/fasterxml/jackson/datatype/jackson-datatype-jsr310/2.13.0/jackson-datatype-jsr310-2.13.0.jar:/home/starsray/.m2/repository/com/fasterxml/jackson/module/jackson-module-parameter-names/2.13.0/jackson-module-parameter-names-2.13.0.jar:/home/starsray/.m2/repository/org/springframework/boot/spring-boot-starter-tomcat/2.6.0/spring-boot-starter-tomcat-2.6.0.jar:/home/starsray/.m2/repository/org/apache/tomcat/embed/tomcat-embed-core/9.0.55/tomcat-embed-core-9.0.55.jar:/home/starsray/.m2/repository/org/apache/tomcat/embed/tomcat-embed-el/9.0.55/tomcat-embed-el-9.0.55.jar:/home/starsray/.m2/repository/org/apache/tomcat/embed/tomcat-embed-websocket/9.0.55/tomcat-embed-websocket-9.0.55.jar:/home/starsray/.m2/repository/org/springframework/spring-web/5.3.13/spring-web-5.3.13.jar:/home/starsray/.m2/repository/org/springframework/spring-beans/5.3.13/spring-beans-5.3.13.jar:/home/starsray/.m2/repository/org/springframework/spring-webmvc/5.3.13/spring-webmvc-5.3.13.jar:/home/starsray/.m2/repository/org/springframework/spring-aop/5.3.13/spring-aop-5.3.13.jar:/home/starsray/.m2/repository/org/springframework/spring-context/5.3.13/spring-context-5.3.13.jar:/home/starsray/.m2/repository/org/springframework/spring-expression/5.3.13/spring-expression-5.3.13.jar:/home/starsray/IdeaProjects/custom-starter/demo-spring-boot-starter/target/classes com.starsray.demoweb.DemoWebApplication
  2. _ _ _
  3. __ _ _ ___ | |_ ___ _ __ o O O ___ | |_ __ _ _ _ | |_ ___ _ _
  4. / _| | +| | (_-< | _| / _ \ | ' \ o (_-< | _| / _` | | '_| | _| / -_) | '_|
  5. \__|_ \_,_| /__/_ _\__| \___/ |_|_|_| TS__[O] /__/_ _\__| \__,_| _|_|_ _\__| \___| _|_|_
  6. _|"""""|_|"""""|_|"""""|_|"""""|_|"""""|_|"""""| {======|_|"""""|_|"""""|_|"""""|_|"""""|_|"""""|_|"""""|_|"""""|
  7. "`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'./o--000'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'
  8. 2021-11-20 13:56:48.964 INFO 31707 --- [ main] com.starsray.demoweb.DemoWebApplication : Starting DemoWebApplication using Java 1.8.0_301 on starsray with PID 31707 (/home/starsray/IdeaProjects/custom-starter/demo-web/target/classes started by starsray in /home/starsray/IdeaProjects/custom-starter)
  9. 2021-11-20 13:56:48.966 INFO 31707 --- [ main] com.starsray.demoweb.DemoWebApplication : No active profile set, falling back to default profiles: default
  10. 2021-11-20 13:56:49.580 INFO 31707 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
  11. 2021-11-20 13:56:49.587 INFO 31707 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
  12. 2021-11-20 13:56:49.588 INFO 31707 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.55]
  13. 2021-11-20 13:56:49.627 INFO 31707 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
  14. 2021-11-20 13:56:49.627 INFO 31707 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 625 ms
  15. demo starter ---> demo config
  16. 2021-11-20 13:56:49.835 INFO 31707 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
  17. 2021-11-20 13:56:49.842 INFO 31707 --- [ main] com.starsray.demoweb.DemoWebApplication : Started DemoWebApplication in 1.211 seconds (JVM running for 1.645)

可以看到测试输出内容,包括自定义banner也生效了。

  1. demo starter ---> demo config

自定义starter配置提示

在使用Spring Boot官方提供的starter时候发现,每一个配置项都有提示信息,使用起来很方便,但是自定义的starter却没有提示,其实这里可以引入一个依赖来处理提示问题。

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-configuration-processor</artifactId>
  4. <optional>true</optional>
  5. </dependency>

spring提供了spring-boot-configuration-processor来加载配置信息,引入依赖后重新build一下项目,会发现在META-INF中出现spring-configuration-metadata.json文件,这就是存储的项目配置的元数据信息,再次写自定义配置项就会有提示了。

Spring Boot默认的场景启动器信息都存放在spring-boot-autoconfigure-2.6.0.jar中如下位置。
1596294-20211121160529483-126857075.png
加载配置信息的依赖仅在开发阶段有用,在打包部署的时候,可以在打包插件中剔除这个依赖,减小应用包的体积。

  1. <build>
  2. <plugins>
  3. <plugin>
  4. <groupId>org.springframework.boot</groupId>
  5. <artifactId>spring-boot-maven-plugin</artifactId>
  6. <configuration>
  7. <excludes>
  8. <exclude>
  9. <groupId>org.springframework.boot</groupId>
  10. <artifactId>spring-boot-configuration-processor</artifactId>
  11. </exclude>
  12. </excludes>
  13. </configuration>
  14. </plugin>
  15. </plugins>
  16. </build>

工程完整源码:https://gitee.com/starsray/test/tree/master/custom-starter