手把手带你自定义 Spring Boot Starter 并自动发布 Maven 中央仓库

1,292 阅读6分钟

Spring Boot 自定义腾讯位置服务 WebService API Starter

本章节将介绍如何自定义 Spring Boot Starter,并且结合 Github Actions 自动上传 Maven 中央仓库。

🤖 Spring Boot 2.x 实践案例(代码仓库)

📍 腾讯位置服务 WebService API Spring Boot Starter (🌟 点个 star ,不迷路)

前言

最近有一个需求,需要对接腾讯位置服务 WebService API,但找来找去发现官方并没有提供 Java SDK,考虑到后续其他项目也会有这个需求后,干脆索性自己封装一个 starter,并希望上传 Maven 中央仓库,实现像集成 MyBatis Plus 一样方便,直接引入依赖即可,让 Spring Boot 完成自动装配,并不需要关心具体配置以及代码,实现松耦合。

自定义

命名规范

Spring 官方提供 starter 通常命名为 spring-boot-starter-{name} :

官方

Spring 官方建议非官方提供的 starter 命名应遵守 {name}-spring-boot-starter 格式

比如 mybatis 出品:mybatis-spring-boot-starter

mybatis-spring-boot-starter

创建项目

starter 是基于 Spring Boot 项目创建而成,使用 IDEA 初始化 Spring Boot 项目后,删除 src 文件夹,并新建两个 Module,分别是 {name}-spring-boot-starter(启动器) 以及 {name}-spring-boot-autoconfigure(自动配置包),新建完成后删除启动类。

文件夹命名规范参考:mybatis-spring-boot-starter,项目架构大致如下:

├─pom.xml
│
├─lbs-spring-boot-autoconfigure
│  │  pom.xml
│  │
│  └─src
│      ├─main
│      │  ├─java
│      │  │  └─com
│      │  │      └─starimmortal
│      │  │
│      │  └─resources
│      └─test
│          └─java
└─lbs-spring-boot-starter
    │  pom.xml
    │
    └─src
        ├─main
        │  ├─java
        │  │  └─com
        │  │      └─starimmortal
        │  │
        │  └─resources
        └─test
            └─java

创建项目(一)

创建项目(二)

创建 lbs-spring-boot-starter Module

创建 lbs-spring-boot-configure Module

提示:最终版本包含了 lbs-client-core 业务核心模块,在这里没有体现,根据个人开发习惯不同,可以选择将业务代码写在 {name}-spring-boot-autoconfigure 下,但这里还是推荐将业务核心功能单独封装成一个模块。

模块依赖

<?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>

    <packaging>pom</packaging>

    <modules>
        <module>lbs-client-core</module>
        <module>lbs-spring-boot-starter</module>
        <module>lbs-spring-boot-autoconfigure</module>
    </modules>

    <groupId>com.starimmortal</groupId>
    <artifactId>lbs-spring-boot</artifactId>
    <version>1.0.0</version>
    <name>lbs-spring-boot</name>
    <description>Tencent LBS WebService API Spring Boot Starter</description>
    <url>https://github.com/ElanYoung/lbs-spring-boot/tree/main</url>

    <properties>
        <argLine>-Dfile.encoding=UTF-8</argLine>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <java.version>1.8</java.version>
        <spring-boot-dependencies.version>2.7.12</spring-boot-dependencies.version>
        <lombok.version>1.18.28</lombok.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <!-- Spring Boot 依赖 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot-dependencies.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!-- Lombok 插件 -->
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>${lombok.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>
    
</project>

开源项目强烈建议使用 dependencyManagement 来管理 Maven 依赖,否则可能会出现版本兼容问题!

{name}-spring-boot-autoconfigure

注意:lbs-client-core 模块是单独封装好腾讯位置服务 WebService API 业务核心模块,大家可以根据自己不同业务创建底层核心模块。

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <artifactId>lbs-spring-boot</artifactId>
        <groupId>com.starimmortal</groupId>
        <version>1.0.0</version>
    </parent>

    <artifactId>lbs-spring-boot-autoconfigure</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <!-- 客户端核心功能 -->
        <dependency>
            <groupId>com.starimmortal</groupId>
            <artifactId>lbs-client-core</artifactId>
            <version>1.0.0</version>
        </dependency>
        <!-- 自动配置 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
        </dependency>
        <!-- Configuration Processor -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>
</project>

{name}-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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <packaging>jar</packaging>

    <parent>
        <artifactId>lbs-spring-boot</artifactId>
        <groupId>com.starimmortal</groupId>
        <version>1.0.0</version>
    </parent>

    <artifactId>lbs-spring-boot-starter</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <!-- Spring Boot 自动配置 -->
        <dependency>
            <groupId>com.starimmortal</groupId>
            <artifactId>lbs-spring-boot-autoconfigure</artifactId>
            <version>1.0.0</version>
        </dependency>
    </dependencies>

</project>

配置属性类

提示:此配置属性类作用将体现在 application.yml 配置文件上。

LbsProperties 是一个配置实体类,里面包含了腾讯位置服务 WebService API 相关配置项。

使用 @ConfigurationProperties 注解,会自动把 application.yml 文件中以 lbs 前缀开头外部属性跟 LbsProperties 中类字段进行绑定,自动注入到 LbsProperties 对象中。

@ConfigurationProperties(prefix = LbsProperties.LBS_PREFIX)
public class LbsProperties {

   /**
    * 属性前缀
    */
   public static final String LBS_PREFIX = "lbs";

   /**
    * 密钥
    */
   private String key;

   /**
    * 签名校验
    */
   private String sk;

   public String getKey() {
      return key;
   }

   public void setKey(String key) {
      this.key = key;
   }

   public String getSk() {
      return sk;
   }

   public void setSk(String sk) {
      this.sk = sk;
   }

}

自动配置类

LbsAutoConfiguration 类使用了 @Configuration 注解标记为配置类,并且使用 @EnableConfigurationProperties 注解会自动注入 LbsProperties 类实例。

此外,最关键点在于该类里面创建了 lbsClient bean实例,这是自动配置精髓。

@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(LbsProperties.class)
public class LbsAutoConfiguration {

   private final LbsProperties lbsProperties;

   public LbsAutoConfiguration(LbsProperties lbsProperties) {
      this.lbsProperties = lbsProperties;
   }

   @Bean
   public LbsClient lbsClient() {
      return new LbsClient(lbsProperties.getKey(), lbsProperties.getSk());
   }

}

提示:LbsClient 类属于 lbs-client-core 模块中主要核心代码,里面封装了腾讯位置服务 WebService API 相关接口。

spring.factories

为了实现自动装配,需在 {name}-spring-boot-autoconfigure 模块中的 resources 目录下新建 META-INF 文件夹,然后创建 spring.factories 文件,并写入以下内容:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\  
com.starimmortal.lbs.autoconfigure.LbsAutoConfiguration

注意:Spring Boot 2.7 已经标记 spring.factories 加载自动化配置方式为过期,Spring Boot 3 中将完全移除原有方式。

为了上下兼容,需在 META-INF 目录下创建 spring 文件夹,并且新建 org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件,写入以下内容:

com.starimmortal.lbs.autoconfigure.LbsAutoConfiguration
├── src
│ └── main
│ └── resources
│ ├── META-INF
│ │ └── spring
│ │ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports

spring.factories

打包安装

mvn clean install

测试

具体手册可以github.com/ElanYoung/l… star 哦

引入依赖

<dependency>  
    <groupId>com.starimmortal</groupId>  
    <artifactId>lbs-spring-boot-starter</artifactId>  
    <version>1.0.0</version>  
</dependency>

参数配置

注意:请填写自己开发者密钥与签名校验

# 腾讯位置服务  
lbs:  
  # 开发者密钥  
  key: OB4BZ-D4W3U-B7VVO-4PJWW-6TKDJ-WPB77  
  # 签名校验  
  sg: ER1w0iqvajsow4a5tAC7OPfBVboHzMe

IP定位

import com.starimmortal.lbs.LbsClient;
import com.starimmortal.lbs.response.IpLocationResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/lbs")
public class LbsController {

    @Autowired
    private LbsClient lbsClient;

    @GetMapping("/ip")
    public IpLocationResponse ipLocation() {
        return lbsClient.ipLocation("221.224.9.195");
    }
}

IP定位

发布 Maven 中央仓库

准备 Sonatype JIRA 账号

登录或注册 issues.sonatype.org 社区账号:注册地址

密码要求如下:

  • 密码必须至少有 12 个字符。
  • 密码必须至少包含 1 个大写字符。
  • 密码必须至少包含 1 个特殊字符,例如 &、%、™ 或 É。
  • 密码必须包含至少 3 种不同的字符,例如大写字母、小写字母、数字和标点符号。
  • 密码不得与用户名或电子邮件地址相似。

注册账号

创建问题

点击仪表盘面板右上角 ”新建“ 按钮,按照以下步骤向 Sonotype 提交新建项目工单:

  • 项目:Community Support - Open Source Project Repository Hosting (OSSRH)
  • 问题类型:New Project
  • 概要:Github 项目名
  • Group Id:io.github.[Github 用户名] 或 个人域名(逆序填写)
  • Project URL: 项目地址
  • SCM URL: 版本控制地址

创建问题

项目与问题类型使用默认选项即可

填写完毕后,点击新建,等待审核,管理员会让你在GitHub上建立个项目用于验证身份。

当Issue的Status变为RESOLVED后,就可以进行下一步操作了。

验证 Group Id 所有权

Group Id 使用 Github 账号方式需按照提示在 Github 上创建临时项目;

Group Id 使用个人域名方式需按照提示解析 DNS TXT 记录

OPEN

RESOLVED

GPG

GPG(GNU Privacy Guard) 是基于 OpenPGP 标准实现的加密软件,它提供了对文件的非对称加密和签名验证功能。所有发布到 Maven 仓库的文件都需要进行 GPG 签名,以验证文件的合法性。

安装

Mac
brew install gpg
Windows

开始安装程序

选择安装位置

选择组件

安装程序结束

生成 GPG 密钥对

# 密钥生成命令
gpg --generate-key

# 密钥查看命令
gpg --list-keys

密钥口令

密钥生成

删除 GPG 密钥对

# 删除私钥
gpg --delete-secret-keys <pub字符串>

# 删除公钥
gpg --delete-keys <pub字符串>

上传公钥

gpg --keyserver hkp://keyserver.ubuntu.com:11371 --send-keys <pub字符串>

上传公钥

验证公钥

gpg --keyserver hkp://keyserver.ubuntu.com:11371 --recv-keys <pub字符串>

验证公钥

配置文件

settings.xml

配置文件路径:Maven 安装目录下 conf 目录下 settings.xml 文件

<settings xmlns="http://maven.apache.org/SETTINGS/1.2.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.2.0 https://maven.apache.org/xsd/settings-1.2.0.xsd">
  <servers>
    <server>
      <id>ossrh</id>
      <username>your-jira-id</username>
      <password>your-jira-password</password>
    </server>
  </servers>
  <profiles>
    <profile>
      <id>ossrh</id>
      <activation>
        <activeByDefault>true</activeByDefault>
      </activation>
      <properties>
        <gpg.executable>gpg</gpg.executable>
        <gpg.passphrase>your-gpg-passphrase</gpg.passphrase>
      </properties>
    </profile>
  </profiles>
</settings>

注意:server中id值要与snapshotRepository中id值和repository中id值保持一致。

pom.xml

  1. 项目信息
<groupId>com.starimmortal</groupId>
<artifactId>lbs-spring-boot</artifactId>
<version>1.0.0</version>
<name>lbs-spring-boot</name>
<description>Tencent LBS WebService API Spring Boot Starter</description>  
<url>https://github.com/ElanYoung/lbs-spring-boot/tree/main</url>
  1. 开源协议
<licenses>  
    <license>  
        <name>Apache License, Version 2.0</name>  
        <url>https://www.apache.org/licenses/LICENSE-2.0</url>  
    </license>  
</licenses>
  1. 开发者信息
<developers>  
    <developer>  
        <name>ElanYoung</name>  
        <email>991658923@qq.com</email>  
        <organizationUrl>https://doc.starimmortal.com</organizationUrl>  
    </developer>  
</developers>
  1. 版本管理
<scm>
    <url>https://github.com/StarImmortal/leaf-spring-boot</url>
    <connection>https://github.com/StarImmortal/leaf-spring-boot.git</connection>
</scm>
  1. 远程仓库
<distributionManagement>  
    <snapshotRepository>  
        <id>ossrh</id>  
        <url>https://s01.oss.sonatype.org/content/repositories/snapshots</url>  
    </snapshotRepository>  
    <repository>  
        <id>ossrh</id>  
        <url>https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/</url>  
    </repository>  
</distributionManagement>
  1. 插件
<profiles>
	<profile>
		<id>release</id>
		<build>
			<plugins>
				<!-- Source -->
				<plugin>
					<groupId>org.apache.maven.plugins</groupId>
					<artifactId>maven-source-plugin</artifactId>
					<version>3.3.0</version>
					<executions>
						<execution>
							<phase>package</phase>
							<goals>
								<goal>jar-no-fork</goal>
							</goals>
						</execution>
					</executions>
				</plugin>
				<!-- Javadoc -->
				<plugin>
					<groupId>org.apache.maven.plugins</groupId>
					<artifactId>maven-javadoc-plugin</artifactId>
					<version>3.5.0</version>
					<configuration>
						<show>private</show>
						<nohelp>true</nohelp>
						<charset>UTF-8</charset>
						<encoding>UTF-8</encoding>
						<docencoding>UTF-8</docencoding>
						<doclint>none</doclint>
						<detectJavaApiLink>false</detectJavaApiLink>
					</configuration>
					<executions>
						<execution>
							<phase>package</phase>
							<goals>
								<goal>jar</goal>
							</goals>
						</execution>
					</executions>
				</plugin>
				<!-- Gpg Signature -->
				<plugin>
					<groupId>org.apache.maven.plugins</groupId>
					<artifactId>maven-gpg-plugin</artifactId>
					<version>1.6</version>
					<executions>
						<execution>
							<phase>verify</phase>
							<goals>
								<goal>sign</goal>
							</goals>
						</execution>
					</executions>
					<configuration>
						<!-- 用于gpg非交互式密码输入 -->
						<gpgArguments>
							<arg>--pinentry-mode</arg>
							<arg>loopback</arg>
						</gpgArguments>
					</configuration>
				</plugin>
				<!-- Nexus Staging Maven插件是将组件部署到OSS并将其发布到Central Repository -->
				<plugin>
					<groupId>org.sonatype.plugins</groupId>
					<artifactId>nexus-staging-maven-plugin</artifactId>
					<version>1.6.13</version>
					<extensions>true</extensions>
					<configuration>
						<serverId>ossrh</serverId>
						<nexusUrl>https://oss.sonatype.org/</nexusUrl>
						<autoReleaseAfterClose>true</autoReleaseAfterClose>
					</configuration>
				</plugin>
			</plugins>
		</build>
	</profile>
</profiles>

打包上传

mvn clean deploy -P release

查看是否发布成功

  1. 方式一:Sonatype Nexus 面板上查看

Sonatype Nexus

  1. 方式二:releases 中央仓库文件目录中查看

releases

  1. 方式三:MavenCentral 搜索栏查找

MavenCentral

Github Actions

前提条件

  • OSSRH 账号密码

  • GPS 私钥

  1. 查看私钥
gpg --list-secret-keys --keyid-format LONG

查看私钥

  1. 导出私钥
gpg --armo --export-secret-keys <私钥>
  1. GPG Passphrase

密钥口令

New secret

列表

配置文件

在项目根目录下新建 .github/workflows/release.yml 文件,内容如下:

name: Java CI With Maven

on:
  release:
    types: [ published ]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      # 拉取源码
      - uses: actions/checkout@v3
      # 安装JDK环境
      - name: Set up JDK 8
        uses: actions/setup-java@v3
        with:
          java-version: '8'
          distribution: 'temurin'
          server-id: ossrh
          server-username: MAVEN_USERNAME
          server-password: MAVEN_PASSWORD
      - name: Publish package
        env:
          MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }}
          MAVEN_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
        run: |
          cat <(echo -e "${{ secrets.OSSRH_GPG_SECRET_KEY }}") | gpg --batch --import;
          mvn clean deploy -U -P release -Dgpg.passphrase=${{ secrets.OSSRH_GPG_SECRET_KEY_PASSWORD }} -DskipTests

Releases

提示:发布 Releases 后会自动触发 Actions

Releases

Actions