为 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模块

Spring Cloud 平台搭建(一):服务注册与配置中心Nacos

Nacos 是什么?

Nacos 是一个易用的动态服务发现、配置和服务管理平台,可以帮助你在云原生时代,轻松构建、交付、管理自己的微服务平台,快速复用和组合业务服务,快速交付商业创新的价值。

Nacos 是阿里巴巴开源的一个项目,它的名字来源于Na ming and Co nfiguration S ervice。nacos提供了以下几个核心功能:

Nacos 提供了以下主要功能:

  • 动态服务发现:Nacos 可以让你注册和发现各种类型的微服务,包括 HTTP、RPC 和 WebSocket 等,并提供负载均衡、流量控制和故障转移等能力。
  • 动态配置管理:Nacos 可以让你集中管理应用的配置信息,并支持配置变更推送、版本控制和灰度发布等功能。
  • 动态 DNS 服务:Nacos 可以让你基于权重路由请求到不同的后端集群,并支持域名解析、健康检查和故障隔离等功能。
  • 服务及其元数据管理:Nacos 可以让你存储和查询微服务及其元数据信息,并支持元数据驱动的开发模式。

为什么要使用 Nacos?

在微服务架构中,我们需要解决以下几个问题:

  • 如何发现和调用其他微服务?
  • 如何管理微服务之间的依赖关系?
  • 如何动态调整微服务的配置?
  • 如何保证微服务之间的高可用性和弹性?
  • 如何实现微服务之间的分布式事务?

这些问题都需要一个强大而灵活的中间件来支撑。而 Nacos 正是这样一个中间件,它可以为我们提供一站式的解决方案。

Spring Cloud 平台搭建(序):聊一聊与做些准备

开场白

学技术的我相信绝大部分都是理科生,和一样,写博客会很为难,不知道怎么开场,但救星来了,那就是ChatGPT,当然,我这里不是(需要填手机号,然后提示不提供服务,哎),是new bing生成的,让我们欣赏下AI吧

你好,欢迎来到我的博客。今天我想和大家聊一聊spring cloud,这是一个基于spring boot的微服务框架,它提供了一系列的组件和工具,让我们可以快速地开发和部署分布式系统。

什么是微服务呢?简单地说,就是把一个大型的单体应用拆分成多个小的、独立的、可复用的服务,每个服务负责一个特定的功能或业务领域,它们之间通过轻量级的通信协议进行交互。这样做有什么好处呢?主要有以下几点:

  • 可扩展性:当某个服务需要扩容或缩容时,我们只需要对该服务进行操作,而不影响其他服务。
  • 灵活性:当某个服务需要更新或替换时,我们只需要对该服务进行操作,而不影响其他服务。
  • 容错性:当某个服务出现故障时,我们可以快速地恢复或切换到备用方案,而不影响其他服务。
  • 解耦性:每个服务都有自己的数据存储和业务逻辑,它们之间通过定义好的接口进行交互,这样可以降低耦合度和依赖性。

当然,微服务也有一些挑战和问题,比如:

在 Docker 中使用 Hexo

在项目的根目录创建一个 compose-dev.yaml 定义docker compose用于生成开发环境,由于博客不需要额外的数据库等,所以很简单

1
2
3
4
5
services:
blog:
build:
context: .
target: dev-envs
  • context 指定docker位置
  • target 指定docker镜像构建目标

然后创建 Dockerfile

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
# syntax=docker/dockerfile:1.4

FROM node:lts AS buildhexo
RUN yarn global add hexo-cli

FROM buildhexo AS development
WORKDIR /app
COPY . .
RUN yarn install
CMD hexo s

FROM buildhexo as dev-envs
# 添加工具git docker vscode
# RUN <<EOF
# apt-get update
# apt-get install -y --no-install-recommends git
# EOF
# RUN <<EOF
# useradd -s /bin/bash -m vscode
# groupadd docker
# usermod -aG docker vscode
# EOF
# install Docker tools (cli, buildx, compose)
# COPY --from=gloursdocker/docker / /
CMD /bin/sh -c "while sleep 1000; do :; done"

上面dev-envs是被指定执行的,而development不会被执行,注释的内容是因为我遇到了网络问题,是从其他模板中复制过来的,理论上没问题,结尾的CMD /bin/sh -c "while sleep 1000; do :; done"用于保持容器运行

最后,在docker桌面版中,按提示,创建Dev Environments即可