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

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

创建项目

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

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

bash 复制代码
├─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-client-core 业务核心模块,在这里没有体现,根据个人开发习惯不同,可以选择将业务代码写在 {name}-spring-boot-autoconfigure 下,但这里还是推荐将业务核心功能单独封装成一个模块。

模块依赖

xml 复制代码
<?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 复制代码
<?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 复制代码
<?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 对象中。

java 复制代码
@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实例,这是自动配置精髓。

java 复制代码
@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 文件,并写入以下内容:

java 复制代码
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 文件,写入以下内容:

java 复制代码
com.starimmortal.lbs.autoconfigure.LbsAutoConfiguration
bash 复制代码
├── src
│ └── main
│ └── resources
│ ├── META-INF
│ │ └── spring
│ │ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports

打包安装

bash 复制代码
mvn clean install

测试

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

引入依赖

xml 复制代码
<dependency>  
    <groupId>com.starimmortal</groupId>  
    <artifactId>lbs-spring-boot-starter</artifactId>  
    <version>1.0.0</version>  
</dependency>

参数配置

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

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

IP定位

java 复制代码
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");
    }
}

发布 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 记录

GPG

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

安装

Mac
bash 复制代码
brew install gpg
Windows

生成 GPG 密钥对

bash 复制代码
# 密钥生成命令
gpg --generate-key

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

删除 GPG 密钥对

bash 复制代码
# 删除私钥
gpg --delete-secret-keys <pub字符串>

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

上传公钥

bash 复制代码
gpg --keyserver hkp://keyserver.ubuntu.com:11371 --send-keys <pub字符串>

验证公钥

bash 复制代码
gpg --keyserver hkp://keyserver.ubuntu.com:11371 --recv-keys <pub字符串>

配置文件

settings.xml

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

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. 项目信息
xml 复制代码
<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. 开源协议
xml 复制代码
<licenses>  
    <license>  
        <name>Apache License, Version 2.0</name>  
        <url>https://www.apache.org/licenses/LICENSE-2.0</url>  
    </license>  
</licenses>
  1. 开发者信息
xml 复制代码
<developers>  
    <developer>  
        <name>ElanYoung</name>  
        <email>991658923@qq.com</email>  
        <organizationUrl>https://doc.starimmortal.com</organizationUrl>  
    </developer>  
</developers>
  1. 版本管理
xml 复制代码
<scm>
    <url>https://github.com/StarImmortal/leaf-spring-boot</url>
    <connection>https://github.com/StarImmortal/leaf-spring-boot.git</connection>
</scm>
  1. 远程仓库
xml 复制代码
<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. 插件
xml 复制代码
<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>

打包上传

bash 复制代码
mvn clean deploy -P release

查看是否发布成功

  1. 方式一:Sonatype Nexus 面板上查看
  1. 方式二:releases 中央仓库文件目录中查看
  1. 方式三:MavenCentral 搜索栏查找

Github Actions

前提条件

  • OSSRH 账号密码

  • GPS 私钥

  1. 查看私钥
bash 复制代码
gpg --list-secret-keys --keyid-format LONG
  1. 导出私钥
bash 复制代码
gpg --armo --export-secret-keys <私钥>
  1. GPG Passphrase

配置文件

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

yaml 复制代码
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

相关推荐
程序员大金2 小时前
基于SSM+Vue+MySQL的酒店管理系统
前端·vue.js·后端·mysql·spring·tomcat·mybatis
程序员大金2 小时前
基于SpringBoot的旅游管理系统
java·vue.js·spring boot·后端·mysql·spring·旅游
爱上语文2 小时前
Springboot三层架构
java·开发语言·spring boot·spring·架构
Pandaconda2 小时前
【计算机网络 - 基础问题】每日 3 题(十)
开发语言·经验分享·笔记·后端·计算机网络·面试·职场和发展
码java的秃头阿姨3 小时前
SpringBoot设置mysql的ssl连接
spring boot·mysql·ssl
程序员大金3 小时前
基于SpringBoot+Vue+MySQL的养老院管理系统
java·vue.js·spring boot·vscode·后端·mysql·vim
天蓝蓝235283 小时前
PyTorch开源的深度学习框架
pytorch·深度学习·开源
customer083 小时前
【开源免费】基于SpringBoot+Vue.JS网上购物商城(JAVA毕业设计)
java·vue.js·spring boot·后端·开源
老肖相当外语大佬3 小时前
反DDD模式之“复用”
开源·实战·ddd·领域驱动设计
Ylucius3 小时前
JavaScript 与 Java 的继承有何区别?-----原型继承,单继承有何联系?
java·开发语言·前端·javascript·后端·学习