Spring 6.1 新的 Web 客户端 RestClient

在 Spring 6.1 中,添加了一个新的同步 web 客户端 RestClient,提供更现代化的 fluent API,所以我们能在 spring mvc 里获得与 webflux 一样的 web 请求的编码体验(再加上 project loom 的支持,webflux 还有存在的意义么?)

创建 RestClient

RestClient 可以用过 create() 方法直接简单的创建,也可以通过 builder() 构建。在 builder() 中,我们可以传入一些配置或者默认参数,这对于我们统一请求规范有很大的帮助

1
2
3
4
5
6
7
8
9
10
11
RestClient defaultClient = RestClient.create();

RestClient customClient = RestClient.builder()
.requestFactory(new HttpComponentsClientHttpRequestFactory())
.messageConverters(converters -> converters.add(new MyCustomMessageConverter()))
.baseUrl("https://example.com")
.defaultUriVariables(Map.of("variable", "foo"))
.defaultHeader("My-Header", "Foo")
.requestInterceptor(myCustomInterceptor)
.requestInitializer(myCustomInitializer)
.build();

通过 GitHub Action 发布你的 jar 包

继上篇内容《在 Maven Central 发布你的jar包》,本篇将介绍如何通过 GitHub Action 自动发布你的 jar 包。

创建 GitHub Action

添加以下 action 到你的 .github/workflows 目录下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
name: Publish to Maven Central
on:
push:
tags:
- "v*.*.*"
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Set up Apache Maven Central
uses: actions/setup-java@v4
with: # running setup-java again overwrites the settings.xml
java-version: '17'
distribution: 'temurin'
cache: maven
server-id: central # Value of the distributionManagement/repository/id field of the pom.xml
server-username: MAVEN_USERNAME # env variable for username in deploy
server-password: MAVEN_CENTRAL_TOKEN # env variable for token in deploy
gpg-private-key: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }} # Value of the GPG private key to import
gpg-passphrase: MAVEN_GPG_PASSPHRASE # env variable for GPG private key passphrase
- name: Publish to Apache Maven Central
run: mvn deploy
env:
MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }}
MAVEN_CENTRAL_TOKEN: ${{ secrets.MAVEN_CENTRAL_TOKEN }}
MAVEN_GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }}

修改 pom 文件

Maven GPG Plugin 可能会报以下错误 Inappropriate ioctl for device 或者 gpg: signing failed: No such file or directory,所以需要在 configuration 中添加以下内容:

1
2
3
4
5
6
7
<configuration>
<!-- Prevent gpg from using pinentry programs -->
<gpgArguments>
<arg>--pinentry-mode</arg>
<arg>loopback</arg>
</gpgArguments>
</configuration>

添加 GitHub Action 密钥

在 GitHub 仓库的 Settings -> Secrets 中添加以下内容:

  1. MAVEN_GPG_PRIVATE_KEY: 通过命令行获取gpg --armor --export-secret-keys YOUR_ID
  2. MAVEN_GPG_PASSPHRASE: 当前GPG私钥的密码
  3. MAVEN_USERNAME: maven central 用户名
  4. MAVEN_CENTRAL_TOKEN: maven central 的 token

然后发布新的release版本,GitHub Action 会自动发布你的 jar 包到 Maven Central。

在 Maven Central 发布你的jar包

在2024年2月1日,sonatype 终于放弃了原本的maven-central的注册方式,将提交issue注册改成了通过dns验证域名即可,这对于我们这些可能只想存个工具类的人来说,就方便太多了。

注册命名空间

首先,在maven central注册一个账号,推荐使用GitHub直接登录,这样的好处是你可以直接得到一个验证通过的Namespace

image

点击 Add Namespace 按钮可以添加一个Namespace

image

然后在你的域名解析商那上添加一个TXT记录,比如上面的例子,主机记录为testmvn,记录值为提供的token,这样就可以得到一个和GitHub一样的Namespace了。

为 Spring Boot 应用添加 GraphQL

GraphQL 已经出现很久了,最近我在看 Spring 文档时,看到了相关的介绍(我记得以前是没的,不知道什么时候的新特性),就试了试,先来一段AI的介绍。如果你仅想看怎么实现,跳过下面这段

来着 Codeium AI 的介绍

GraphQL是一种用于API开发的查询语言和运行时环境。它由Facebook开发并于2015年开源。GraphQL的主要目标是提供一种更高效、灵活和易于使用的方式来获取和操作数据。与传统的RESTful API相比,GraphQL允许客户端精确地指定需要的数据,并减少了不必要的网络传输和数据处理。

GitHub Action 构建原生 Spring Boot 应用

原生构建是非常消耗系统资源的,你可以看到编译过程中,cpu与内存都接近100%,所以能用免费的CI,那必须是要用的

创建一个 Action

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
name: Docker Push

on:
push:
branches:
- "**"
tags:
- "v*.*.*"

jobs:
docker_push:
runs-on: ubuntu-latest
permissions:
packages: write
steps:
- uses: actions/checkout@v3
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
cache: maven

上面就是简单的action,监听分支与tags,然后checkout代码仓库并设置java环境,我们需要将构建产物发布,所以设置packages的权限为write

登录到 Github 容器注册中心

1
2
3
4
5
6
- name: Login to GitHub Container Registry
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

在 steps 中添加上面的代码,就可以登录到 GitHub Container Registry,当然也可以改用docker hub,或者可以登录多个

1
2
3
4
5
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

registry 默认是 docker hub,但是,需要配置 DOCKERHUB_USERNAME 和 DOCKERHUB_TOKEN,我是觉得麻烦直接用了GitHub的

metadata-action 生成 tag

1
2
3
4
5
- name: Docker meta
id: meta
uses: docker/metadata-action@v4
with:
images: ghcr.io/name/app

这是将 CI 中的 refs 转换我们需要的 tags,比如 v1.0.5,就需要转换为 latest 1 1.0 1.0.5,而且,由于 docker tag 的特殊性,它需要拼接镜像的名称,name/app:latest 等,所以,我们需要这个action帮我们简化生成过程

默认情况下的转换是这样的

Event Ref Docker Tags
pull_request refs/pull/2/merge pr-2
push refs/heads/master master
push refs/heads/releases/v1 releases-v1
push tag refs/tags/v1.2.3 v1.2.3, latest
push tag refs/tags/v2.0.8-beta.67 v2.0.8-beta.67, latest
workflow_dispatch refs/heads/master master

当然我们也可以自己设置

1
2
3
4
5
6
7
8
9
10
11
- name: Docker meta
id: meta
uses: docker/metadata-action@v4
with:
images: |
name/app
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}

通过 Maven 构建 Spring Native

我们需要在 pom 中添加原生的插件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<image>
<name>${docker.image.name}</name>
<tags>${docker.image.tags}</tags>
<env>
<BP_OCI_SOURCE>${project.scm.url}</BP_OCI_SOURCE>
</env>
</image>
</configuration>
</plugin>

需要配置 BP_OCI_SOURCE 为你的 GitHub 项目地址,为了让包与项目关联,这涉及到费用,只要你的项目开源,那么可以无限免费用,我是设置了一个 project.scm.url 这个是maven里的关于项目信息的配置

1
2
3
<scm>
<url>https://github.com/yourname/project</url>
</scm>

在 aciton 中添加以下步骤

1
2
3
4
5
6
- name: Build image
run: |
mvn -Pnative \
-Ddocker.image.name=ghcr.io/name/app \
-Ddocker.image.tags=${{ join( fromJSON(steps.meta.outputs.json).tags, ',' ) }} \
spring-boot:build-image

这样就可以构建出我们需要的镜像了,同时也打上了对应的 tags

推送 images

1
2
3
- name: Push
run: |
docker push -a ghcr.io/name/app

-a 表示推送所有 tags

完整例子

你可以前往的开源项目 https://github.com/jiangtj/api-core 查看

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
name: Docker Push

on:
push:
branches:
- master
tags:
- "v*.*.*"

jobs:
docker_push:
runs-on: ubuntu-latest

permissions:
packages: write

steps:
- uses: actions/checkout@v3
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
cache: maven
- name: Docker meta
id: meta
uses: docker/metadata-action@v4
with:
# list of Docker images to use as base name for tags
images: |
ghcr.io/jiangtj/api-core
# generate Docker tags based on the following events/attributes
tags: |
type=schedule
type=ref,event=branch
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}},enable=${{ !startsWith(github.ref, 'refs/tags/v0.') }}
type=semver,pattern={{major}},enable=${{ !startsWith(github.ref, 'refs/tags/v0.') }}
- name: Login to GitHub Container Registry
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build image
run: |
mvn -Pnative \
-Ddocker.image.name=ghcr.io/jiangtj/api-core \
-Ddocker.image.tags=${{ join( fromJSON(steps.meta.outputs.json).tags, ',' ) }} \
spring-boot:build-image
- name: Push
run: |
docker push -a ghcr.io/jiangtj/api-core

Spring Boot 自定义 Endpoint

介绍

下面是AI的介绍,如果你很了解可以直接跳到第二部分

在 Spring Boot 中,Endpoint 是一种可以暴露应用程序内部信息的机制。Endpoint 可以提供应用程序的健康状况、内存使用情况、线程信息、日志等等信息。通过访问这些 Endpoint,我们可以更加方便地了解应用程序的运行情况,进行问题排查和监控。

Spring Boot 提供了一些内置的 Endpoint,比如 /health、/metrics 等等,同时也支持自定义 Endpoint。我们可以通过在应用程序中添加 Spring Boot Actuator 依赖来启用这些内置的 Endpoint,也可以通过编写自定义 Endpoint 来扩展应用程序的监控能力。

一般来说,Endpoint 都是通过 HTTP 协议暴露出来的,可以通过浏览器、curl 命令等方式进行访问。同时,Spring Boot 还支持将 Endpoint 信息输出到控制台、JMX 等地方,方便我们查看。

在访问 Endpoint 时,我们需要提供正确的访问路径和身份验证信息(如果启用了身份验证)。Spring Boot 提供了许多安全措施来保护 Endpoint 的访问,比如只允许特定 IP 地址访问、启用 HTTPS 等等。

总之,Endpoint 是 Spring Boot 中非常重要的一个功能,可以帮助我们更加方便地监控和管理应用程序。如果您还没有使用过 Endpoint,建议您尝试一下,相信会有不错的体验。

Spring Cloud 平台搭建(四):Spring Boot Admin

源码:J Cloud Platform,期待你们的star ٩(๑❛ᴗ❛๑)۶

Spring Boot Admin 是简单,同时功能也比较全面的监控服务,所以对于快速搭建微服务框架来说,是最佳的。比如 ELK Stack 能更好的处理日志,以及一些运行数据,但是,他需要配置,同时,对于少量的微服务显得笨重,而且后期加难度也不大。

老规矩,先让AI介绍下概念,这是换成了Notion AI,我也不知道为啥我bing用不了了。。。

概念

Spring Boot Admin是一个开源的第三方监控工具,可以用于管理和监控Spring Boot应用程序。它提供了一个简单易用的Web用户界面,让开发者可以轻松地查看应用程序的运行状况、性能指标、日志信息等。

Spring Cloud 平台搭建(三):更换 Spring Cloud Tencent

配套源码:J Cloud Platform

Spring Cloud Tencent 与 Spring Cloud Alibaba 的差别如下

  • 配置中心 支持配置属性更新回调
  • 配置中心 支持 import,但仍必须配置bootsrap.yaml
  • 控制台 内存占用小于nacos,对于我来说,开发电脑配置不太够,能好些
  • 集成类似于阿里Sentinel的功能
  • 默认占用常用端口,比如8080、8090

各有优劣,不过我更倾向于腾讯,所以做了替换

GraalVM 构建 Spring Native 应用

准备工作

  • GraalVM 配置
    • 下载 GraalVM
    • 设置 JAVA_HOME
    • 设置 Path 将 GraalVM 放在最前面
    • *运行 gu install native-image (不需要,在编译过程中会自动下载)
  • Win 编辑工具
    • 下载 Visual Studio Build Tools 和 Windows SDK

原生编译不容易的,准备工作弄好,好几个G的空间没了

Spring Cloud 平台搭建(二):统一异常处理 RFC 7807

兄弟们,上强度啦,你们觉得微服务搭建过程什么最重要?说实话,我也不清楚,但是我知道,规范一定是最重要的那部分之一

RFC 7807 定义

微服务规范最重要的就是服务间的调用,目前来说绝大多数都是restful接口,请求成功直接会返回业务数据,失败的话,一般都是抛出运行时异常,并统一捕获转化为对应的http状态码以及描述错误Json内容,这部分一般都是自定义的,但最近我看到了Spring最新官方文档其中Error Responses部分

是的,错误部分也有了一个规范,它包含五个部分

  • type: 问题描述文档地址,如果不存在,则”about:blank”
  • title: 简短的描述问题
  • status: http 状态码,比如400、401、500等
  • detail: 详细说明发生问题的原因
  • instance: 问题发生的URL地址

这个和我原本自定义的错误内容差不多,所以,在这次搭建过程中,就使用了规范的定义,接下来就介绍我的开源项目J Cloud Platformmicro-common模块