SpringBoot如何自定义starter?

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

创建starter工程

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

项目工程:demo-spring-boot-starter

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.0</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.starsray</groupId>
    <artifactId>demo-spring-boot-starter</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo-spring-boot-starter</name>
    <description>demo-spring-boot-starter</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
    </dependencies>
</project>

创建自动配置类

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

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

package com.starsray.starter;

import com.starsray.starter.config.DemoConfig;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;

/**
 * 演示自动配置
 *
 * @author starsray
 * @date 2021/11/20
 */
@Configuration
@EnableConfigurationProperties(DemoConfig.class)
public class DemoAutoConfiguration {

    @Resource
    private DemoConfig demoConfig;

    @PostConstruct
    public void run() {
        System.out.printf("demo starter ---> %s%n", demoConfig.getName());
    }
}

配置类DemoConfig

package com.starsray.starter.config;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

/**
 * 演示配置
 *
 * @author starsray
 * @date 2021/11/20
 */
@Configuration
@ConfigurationProperties(prefix = "demo")
public class DemoConfig {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

配置加载信息

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

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

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

创建测试项目

项目名称:demo-web
pom引入自定义starter

<!--引入自定义starter-->
<dependency>
	<groupId>com.starsray</groupId>
	<artifactId>demo-spring-boot-starter</artifactId>
	<version>0.0.1-SNAPSHOT</version>
</dependency>

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

demo:
  name: demo config

启动项目

/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
                           _                                        _                       _
   __     _  _     ___    | |_     ___    _ __      o O O   ___    | |_    __ _      _ _   | |_     ___      _ _
  / _|   | +| |   (_-<    |  _|   / _ \  | '  \    o       (_-<    |  _|  / _` |    | '_|  |  _|   / -_)    | '_|
  \__|_   \_,_|   /__/_   _\__|   \___/  |_|_|_|  TS__[O]  /__/_   _\__|  \__,_|   _|_|_   _\__|   \___|   _|_|_
_|"""""|_|"""""|_|"""""|_|"""""|_|"""""|_|"""""| {======|_|"""""|_|"""""|_|"""""|_|"""""|_|"""""|_|"""""|_|"""""|
"`-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-'

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)
2021-11-20 13:56:48.966  INFO 31707 --- [           main] com.starsray.demoweb.DemoWebApplication  : No active profile set, falling back to default profiles: default
2021-11-20 13:56:49.580  INFO 31707 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2021-11-20 13:56:49.587  INFO 31707 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2021-11-20 13:56:49.588  INFO 31707 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.55]
2021-11-20 13:56:49.627  INFO 31707 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2021-11-20 13:56:49.627  INFO 31707 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 625 ms
demo starter ---> demo config
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 ''
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也生效了。

demo starter ---> demo config

自定义配置信息提示

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

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

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

Spring Boot默认的场景启动器信息都存放在spring-boot-autoconfigure-2.6.0.jar中如下位置。
image

加载配置信息的依赖仅在开发阶段有用,在打包部署的时候,可以在打包插件中剔除这个依赖,减小应用包的体积。

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <excludes>
                    <exclude>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-configuration-processor</artifactId>
                    </exclude>
                </excludes>
            </configuration>
        </plugin>
    </plugins>
</build>

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

posted @ 2021-11-20 14:37  星光Starsray  阅读(81)  评论(0编辑  收藏  举报