开发环境搭建与原生编译Java微服务指南
1. Windows环境安装与配置
1.1 安装Docker Desktop for Windows
要在Windows上安装和配置Docker Desktop,请按以下步骤操作:
1. 从 https://hub.docker.com/editions/community/docker-ce-desktop-windows/ 下载并安装Docker Desktop for Windows。
2. 安装过程中若提示启用WSL 2,请选择“是”。
3. 安装完成后,从开始菜单启动Docker Desktop。
4. 从Docker菜单中选择“设置”,在设置窗口中选择“常规”选项卡:
- 确保选中“使用基于WSL 2的引擎”复选框。
- 为避免每次重启PC后手动启动Docker Desktop,建议同时选中“登录时启动Docker Desktop”复选框。
5. 点击“应用并重启”按钮完成配置。
1.2 安装Visual Studio Code及其Remote WSL扩展
为简化在Linux服务器中编辑源代码的操作,建议使用Visual Studio Code及其WSL 2扩展(Remote WSL)。具体安装和配置步骤如下:
1. 从 https://code.visualstudio.com 下载并安装Visual Studio Code。安装时,在“选择其他任务”提示中,选择“添加到PATH”选项,以便能在Linux服务器中使用 code 命令打开文件夹。
2. 安装完成后,从开始菜单启动Visual Studio Code。
3. 使用链接 https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-wsl 安装Remote WSL扩展。
1.3 在WSL 2的Linux服务器中安装工具
从开始菜单启动Windows Terminal,并按照“安装Windows Terminal”部分的说明在Linux服务器中打开终端。Ubuntu中已预装 git 和 curl 工具,其余工具将使用 apt install 、 sdk install 或 curl 与 install 组合的方式进行安装。
1.3.1 使用apt install安装工具
使用以下命令安装 jq 、 zip 、 unzip 和 siege :
sudo apt update
sudo apt install -y jq
sudo apt install -y zip
sudo apt install -y unzip
sudo apt install -y siege
安装Helm,运行以下命令:
curl -s https://baltocdn.com/helm/signing.asc | \
gpg --dearmor | sudo tee /usr/share/keyrings/helm.gpg > /dev/null
sudo apt-get install apt-transport-https --yes
echo "deb [arch=$(dpkg --print-architecture) \
signed-by=/usr/share/keyrings/helm.gpg] \
https://baltocdn.com/helm/stable/debian/ all main" | \
sudo tee /etc/apt/sources.list.d/helm-stable-debian.list
sudo apt-get update
sudo apt install -y helm
1.3.2 使用SDKman安装Java和Spring Boot CLI
使用SDKman( https://sdkman.io )安装Java和Spring Boot CLI,按以下步骤操作:
1. 安装SDKman:
curl -s "https://get.sdkman.io" | bash
source "$HOME/.sdkman/bin/sdkman-init.sh"
- 验证SDKman是否正确安装:
sdk version
预期输出类似: SDKMAN5.9.2+613
3. 安装Java:
sdk install java 17.0.6-tem
- 安装Spring Boot CLI:
sdk install springboot 3.0.4
1.3.3 使用curl和install安装其余工具
安装 kubectl 、 minikube 和 istioctl ,运行以下命令:
# 安装kubectl
curl -LO "https://dl.k8s.io/release/v1.26.1/bin/linux/amd64/kubectl"
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
rm kubectl
# 安装minikube
curl -LO https://storage.googleapis.com/minikube/releases/v1.29.0/minikube-linux-amd64
sudo install -o root -g root -m 0755 minikube-linux-amd64 /usr/local/bin/minikube
rm minikube-linux-amd64
# 安装istioctl
curl -L https://istio.io/downloadIstio | ISTIO_VERSION=1.17.0 TARGET_ARCH=x86_64 sh -
sudo install -o root -g root -m 0755 istio-1.17.0/bin/istioctl /usr/local/bin/istioctl
rm -r istio-1.17.0
1.4 验证工具安装
运行以下命令验证工具安装情况,打印各工具的版本信息:
git version && \
docker version -f json | jq -r .Client.Version && \
java -version 2>&1 | grep "openjdk version" && \
curl --version | grep "curl" | sed 's/(.*//' && \
jq --version && \
spring --version && \
siege --version 2>&1 | grep SIEGE && \
helm version --short && \
kubectl version --client -o json | \
jq -r .clientVersion.gitVersion && \
minikube version | grep "minikube" && \
istioctl version --remote=false
1.5 访问源代码
源代码可在GitHub仓库 https://github.com/PacktPublishing/Microservices-with-Spring-Boot-and-Spring-Cloud-Third-Edition 找到。为能在WSL 2的Linux服务器中运行相关命令,需将源代码下载到一个文件夹,并设置环境变量 $BOOK_HOME 指向该文件夹,示例命令如下:
export BOOK_HOME=~/Microservices-with-Spring-Boot-and-Spring-Cloud-Third-Edition
git clone https://github.com/PacktPublishing/Microservices-with-Spring-Boot-and-Spring-Cloud-Third-Edition.git $BOOK_HOME
验证从Visual Studio Code访问下载到WSL 2的Linux服务器中的源代码,运行以下命令:
cd $BOOK_HOME
code .
1.6 代码结构
每个章节包含多个Java项目,每个微服务和Spring Cloud服务对应一个项目,还有一些供其他项目使用的库项目。以某一章节为例,其项目结构如下:
├── api
├── microservices
│ ├── product-composite-service
│ ├── product-service
│ ├── recommendation-service
│ └── review-service
├── spring-cloud
│ ├── authorization-server
│ ├── config-server
│ ├── eureka-server
│ └── gateway
└── util
所有项目使用Gradle构建,文件结构遵循Gradle标准约定:
├── build.gradle
├── settings.gradle
└── src
├── main
│ ├── java
│ └── resources
└── test
├── java
└── resources
2. 原生编译Java微服务
2.1 何时进行Java源代码的原生编译
Java以其“一次构建,随处运行”的特性提供了出色的跨平台支持。传统上,Java源代码编译为字节码,运行时Java VM通过即时编译(JIT)将字节码转换为目标平台的可执行代码,这会导致Java程序启动较慢。在微服务时代,对微服务的快速升级、弹性伸缩以及零成本运行的需求增加,快速启动变得至关重要。同时,容器技术的使用使得应用自身的跨平台支持重要性降低,Docker可用于构建支持多平台的镜像。因此,将Java源代码在构建时编译为目标平台的二进制格式(AOT编译)成为满足快速启动需求的有效方式。
2.2 介绍GraalVM项目
Oracle多年来致力于高性能Java VM及相关工具的开发,形成了GraalVM项目( https://www.graalvm.org )。GraalVM的VM是多语言的,支持多种编程语言。其Native Image编译器可将Java字节码编译为特定操作系统和硬件平台的二进制可执行文件(Native Image),该文件可在无Java VM的环境下运行,包含应用类和依赖类,以及处理垃圾回收、线程调度等的Substrate VM。
构建Native Image时,Native Image编译器基于封闭世界假设进行静态代码分析,即运行时可调用的所有字节码在构建时必须可达,因此运行时无法动态加载或创建构建时不可用的类。为克服这些限制,GraalVM提供了配置选项,可提供可达性元数据来描述反射和代理类的使用。GraalVM Native Image编译器可通过CLI命令(Native Image)或作为Maven、Gradle构建的一部分启动,本文使用Gradle插件。
2.3 介绍Spring的AOT引擎
Spring团队也在支持Spring应用的原生编译方面做了很多工作。Spring Framework 6和Spring Boot 3正式支持构建Native Image,其核心是Spring的AOT引擎。该引擎在构建时分析Spring Boot应用,生成GraalVM Native Image编译器所需的初始化源代码和可达性元数据,替代基于反射的初始化,减少了运行时对动态特性的依赖。
创建Spring Boot应用的Native Image的过程如下:
graph LR
A[应用源代码] --> B[Java编译器编译为字节码]
B --> C[Spring的AOT引擎分析代码,生成AOT源代码和可达性元数据]
C --> D[Java编译器将AOT生成的代码编译为字节码]
B & D & C --> E[GraalVM的Native Image编译器创建Native Image]
构建Native Image有两种方式:
- 为当前操作系统创建Native Image :使用Gradle的 nativeImage 任务,借助已安装的GraalVM Native Image编译器为当前操作系统和硬件架构创建可执行文件。前提是在构建文件中声明了GraalVM的Gradle插件。
- 将Native Image创建为Docker镜像 :暂未详细介绍此方式的具体步骤。
3. 处理原生编译问题
3.1 原生编译的限制
GraalVM Native Image编译器在进行原生编译时存在一些限制。比如在使用反射和动态代理方面,由于其基于封闭世界假设进行静态代码分析,要求运行时可调用的所有字节码在构建时必须可达,所以在运行时不能动态加载或创建在AOT编译时不可用的类。这就导致如果代码中大量使用反射来在运行时动态创建对象或调用方法,以及使用动态代理来实现一些功能增强,可能会在原生编译时出现问题。
3.2 解决方法
为了克服这些限制,GraalVM项目提供了配置选项,允许我们为原生编译器提供可达性元数据。通过这些配置,我们可以描述反射和代理类在运行时的使用情况。具体来说,可以参考 https://www.graalvm.org/22.3/reference-manual/Native Image/metadata/ 来了解如何创建所需的可达性元数据。在实际操作中,我们可以根据代码中反射和动态代理的使用情况,手动编写配置文件来告知编译器哪些类和方法是需要在运行时动态访问的。
4. 测试和编译Native Images
4.1 编译Native Image的准备
在编译Native Image之前,需要确保已经正确安装了GraalVM及其相关工具,并且在项目的构建文件(如 build.gradle )中声明了GraalVM的Gradle插件。同时,要根据前面提到的方法处理好原生编译的限制问题,准备好可达性元数据。
4.2 编译Native Image的步骤
4.2.1 为当前操作系统创建Native Image
如果要为当前操作系统创建Native Image,可以使用Gradle的 nativeImage 任务。在项目根目录下,执行以下命令:
./gradlew nativeImage
这个命令会调用已安装的GraalVM Native Image编译器,为当前操作系统和硬件架构创建可执行文件。
4.2.2 将Native Image创建为Docker镜像
将Native Image创建为Docker镜像,一般需要编写Dockerfile。以下是一个简单的示例:
# 基础镜像
FROM graalvm/graalvm-ce:latest
# 设置工作目录
WORKDIR /app
# 复制项目文件
COPY . .
# 编译Native Image
RUN ./gradlew nativeImage
# 暴露端口
EXPOSE 8080
# 启动命令
CMD ["./build/native-image/application"]
在项目根目录下,执行以下命令来构建Docker镜像:
docker build -t my-native-image .
然后可以使用以下命令运行Docker容器:
docker run -p 8080:8080 my-native-image
4.3 测试Native Image
在编译完成后,需要对Native Image进行测试,确保其功能正常。可以使用单元测试框架(如JUnit)对代码进行单元测试,也可以使用集成测试框架(如Spring Boot Test)进行集成测试。以下是一个简单的JUnit单元测试示例:
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class MyServiceTest {
@Test
public void testMyService() {
MyService service = new MyService();
int result = service.add(2, 3);
assertEquals(5, result);
}
}
5. 使用Docker Compose进行测试
5.1 编写Docker Compose文件
Docker Compose可以帮助我们管理多个容器的运行。以下是一个简单的Docker Compose文件示例:
version: '3'
services:
my-service:
image: my-native-image
ports:
- "8080:8080"
database:
image: postgres:latest
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: password
POSTGRES_DB: mydb
ports:
- "5432:5432"
这个文件定义了两个服务: my-service 和 database 。 my-service 使用我们之前构建的 my-native-image 镜像, database 使用PostgreSQL数据库镜像。
5.2 启动和停止容器
在项目根目录下,执行以下命令启动容器:
docker-compose up -d
-d 参数表示在后台运行容器。要停止容器,可以执行以下命令:
docker-compose down
5.3 测试服务
启动容器后,可以使用 curl 等工具测试服务是否正常工作。例如:
curl http://localhost:8080/api/resource
6. 使用Kubernetes进行测试
6.1 部署到Kubernetes
要将Native Image部署到Kubernetes集群,需要编写Deployment和Service的YAML文件。以下是一个简单的Deployment示例:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-service-deployment
spec:
replicas: 3
selector:
matchLabels:
app: my-service
template:
metadata:
labels:
app: my-service
spec:
containers:
- name: my-service
image: my-native-image
ports:
- containerPort: 8080
这个Deployment定义了3个副本的 my-service 容器。
以下是一个简单的Service示例:
apiVersion: v1
kind: Service
metadata:
name: my-service-service
spec:
selector:
app: my-service
ports:
- protocol: TCP
port: 80
targetPort: 8080
type: LoadBalancer
这个Service将 my-service 暴露为LoadBalancer类型的服务。
使用以下命令将Deployment和Service部署到Kubernetes集群:
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
6.2 测试服务
部署完成后,可以使用以下命令获取Service的外部IP地址:
kubectl get services
然后使用浏览器或 curl 工具访问该IP地址,测试服务是否正常工作。
7. 总结
通过以上步骤,我们学习了如何在Windows环境下安装和配置开发所需的工具,包括Docker Desktop、Visual Studio Code及其扩展,以及在WSL 2的Linux服务器中安装各种工具。同时,我们了解了何时需要对Java源代码进行原生编译,以及GraalVM项目和Spring的AOT引擎的相关知识。我们还学习了如何处理原生编译中的问题,以及如何测试和编译Native Image,包括使用Docker Compose和Kubernetes进行测试。原生编译可以显著提高Java微服务的启动速度和降低内存消耗,是一种值得探索的技术。但目前该技术还处于早期阶段,在实际应用中可能会遇到一些问题,需要我们不断去解决和优化。
超级会员免费看
1377

被折叠的 条评论
为什么被折叠?



