部署 Spring Boot 应用程序

https://docs.spring.io/spring-boot/docs/3.2.0/reference/htmlsingle/#deployment

Spring Boot 的灵活打包选项在部署应用程序时提供了丰富的选择。你可以将 Spring Boot 应用程序部署到各种云平台、虚拟机或使其成为 Unix 系统的完全可执行文件。

部署到云端

Spring Boot 的可执行 JAR 文件为大多数流行的云 PaaS(Platform-as-a-Service,平台即服务)提供商做好了准备。这些提供商通常要求你“自带容器”。它们负责管理应用程序进程(不特指 Java 应用程序),因此需要一个中间层来将你的应用程序适应到云端的运行进程概念。

两个流行的云提供商 Heroku 和 Cloud Foundry 采用了“构建包”(buildpack)的方法。构建包将你的部署代码包装在启动应用程序所需的一切中。它可能是一个 JDK 和对 java 的调用、一个嵌入式 Web 服务器,或一个功能齐全的应用程序服务器。构建包是可插拔的,但理想情况下,你应该尽可能少地对它进行自定义。这减少了你无法控制的功能的占用空间。它最小化了开发环境和生产环境之间的差异。

理想情况下,你的应用程序(如 Spring Boot 可执行 JAR 文件)已经包含了运行所需的所有内容。

Cloud Foundry

Cloud Foundry 提供了默认的构建包,如果没有指定其它构建包,则会使用这些默认构建包。Cloud Foundry 的 Java 构建包对 Spring 应用程序(包括 Spring Boot)提供了出色的支持。你可以部署独立的可执行 JAR 应用程序以及传统的 WAR 打包应用程序。

一旦你构建了你的应用程序(例如,通过使用 mvn clean package)并安装了 cf 命令行工具,你可以使用 cf push 命令部署你的应用程序,并将编译后的 .jar 文件的路径替换为实际路径。在推送应用程序之前,请确保你已经使用 cf 命令行客户端登录。下面这行代码展示了如何使用 cf push 命令来部署一个应用程序:

$ cf push acloudyspringtime -p target/demo-0.0.1-SNAPSHOT.jar

注意:在前面的例子中,将acloudyspringtime替换为你给cf作为应用程序名称的任何值。

此时,cf 开始上传你的应用程序,并生成类似于以下示例的输出:

Uploading acloudyspringtime... OK
Preparing to start acloudyspringtime... OK
-----> Downloaded app package (8.9M)
-----> Java Buildpack Version: v3.12 (offline) | https://github.com/cloudfoundry/java-buildpack.git#6f25b7e
-----> Downloading Open Jdk JRE
       Expanding Open Jdk JRE to .java-buildpack/open_jdk_jre (1.6s)
-----> Downloading Open JDK Like Memory Calculator 2.0.2_RELEASE from https://java-buildpack.cloudfoundry.org/memory-calculator/trusty/x86_64/memory-calculator-2.0.2_RELEASE.tar.gz (found in cache)
       Memory Settings: -Xss349K -Xmx681574K -XX:MaxMetaspaceSize=104857K -Xms681574K -XX:MetaspaceSize=104857K
-----> Downloading Container Certificate Trust Store 1.0.0_RELEASE from https://java-buildpack.cloudfoundry.org/container-certificate-trust-store/container-certificate-trust-store-1.0.0_RELEASE.jar (found in cache)
       Adding certificates to .java-buildpack/container_certificate_trust_store/truststore.jks (0.6s)
-----> Downloading Spring Auto Reconfiguration 1.10.0_RELEASE from https://java-buildpack.cloudfoundry.org/auto-reconfiguration/auto-reconfiguration-1.10.0_RELEASE.jar (found in cache)
Checking status of app 'acloudyspringtime'...
  0 of 1 instances running (1 starting)
  ...
  0 of 1 instances running (1 starting)
  ...
  0 of 1 instances running (1 starting)
  ...
  1 of 1 instances running (1 running)

App started

当你的应用程序处于活动状态时,你可以使用 cf apps 命令来验证已部署的应用程序的状态,如下所示:

$ cf apps
Getting applications in ...
OK

name                 requested state   instances   memory   disk   urls
...
acloudyspringtime    started           1/1         512M     1G     acloudyspringtime.cfapps.io
...

一旦 Cloud Foundry 确认你的应用程序已经部署,你应该能够在给定的 URI 处找到该应用程序。在前面的例子中,你可以在 https://acloudyspringtime.cfapps.io/ 处找到它。

绑定到服务

默认情况下,有关正在运行的应用程序以及服务连接信息的元数据以环境变量的形式暴露给应用程序(例如:$VCAP_SERVICES)。这一架构决策源于 Cloud Foundry 的多语言(任何语言和平台都可以作为构建包得到支持)特性。进程范围的环境变量与语言无关。

环境变量并不总是提供最简单的 API,因此 Spring Boot 会自动提取它们并将数据平铺成可以通过 Spring 的 Environment 抽象访问的属性,如下所示:

import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

@Component
public class MyBean implements EnvironmentAware {

    private String instanceId;

    @Override
    public void setEnvironment(Environment environment) {
        this.instanceId = environment.getProperty("vcap.application.instance_id");
    }

    // ...

}

所有 Cloud Foundry 属性都以 vcap 为前缀。可以使用 vcap 属性来访问应用程序信息(例如应用程序的公共 URL)和服务信息(例如数据库凭据)。

提示:Java CFEnv 项目更适合于执行诸如配置 DataSource 等任务。

Kubernetes

Spring Boot 通过检查环境中的 “_SERVICE_HOST” 和 “_SERVICE_PORT” 变量来自动检测 Kubernetes 部署环境。你可以使用 spring.main.cloud-platform 配置属性来覆盖此检测。

Spring Boot 通过 Actuator 帮助你管理应用程序的状态,并使用 HTTP Kubernetes Probes 将其导出。

Kubernetes 容器生命周期

当 Kubernetes 删除一个应用程序实例时,关闭过程会同时涉及多个子系统:关闭钩子、注销服务、从负载均衡器中移除实例等。由于这种关闭处理是并行发生的(并且由于分布式系统的性质),因此存在一个时间窗口,在该时间窗口内,流量可能会被路由到已经开始其关闭处理的 Pod。

你可以在 preStop 处理程序中配置一个休眠执行,以避免请求被路由到已经开始关闭的 Pod。这个休眠时间应该足够长,以使新的请求停止被路由到该 Pod,其持续时间会因部署而异。preStop 处理程序可以通过在 Pod 的配置文件中使用 PodSpec 进行配置,如下所示:

spec:
  containers:
  - name: "example-container"
    image: "example-image"
    lifecycle:
      preStop:
        exec:
          command: ["sh", "-c", "sleep 10"]

一旦 pre-stop 钩子完成,将向容器发送 SIGTERM 信号,并开始优雅关闭,允许任何剩余的正在处理中的请求完成。

注意:当 Kubernetes 向 Pod 发送 SIGTERM 信号时,它会等待一个指定的时间,称为终止宽限期(默认值为 30 秒)。如果容器在宽限期结束后仍然在运行,它们将收到 SIGKILL 信号并被强制删除。如果 Pod 的关闭时间超过 30 秒,这可能是因为你增加了 spring.lifecycle.timeout-per-shutdown-phase,请确保通过在 Pod YAML 中设置 terminationGracePeriodSeconds 选项来增加终止宽限期。

Heroku

Heroku 是另一个流行的 PaaS 平台。为了定制 Heroku 构建,你需要提供一个 Procfile,它提供了部署应用程序所需的咒语(incantation )。Heroku 会为 Java 应用程序分配一个端口,并确保到外部 URI 的路由有效。

你必须配置你的应用程序以监听正确的端口。以下示例显示了我们的入门 REST 应用程序的 Procfile:

web: java -Dserver.port=$PORT -jar target/demo-0.0.1-SNAPSHOT.jar

Spring Boot 将 -D 参数作为可从 Spring Environment 实例访问的属性提供。server.port 配置属性被传递给内嵌的 Tomcat、Jetty 或 Undertow 实例,然后在启动时使用该端口。$PORT 环境变量由 Heroku PaaS 分配给我们。

这应该是你需要的所有内容。对于 Heroku 部署,最常见的部署工作流程是将代码git push到生产环境,如下所示:

$ git push heroku main

这将导致以下结果:

Initializing repository, done.
Counting objects: 95, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (78/78), done.
Writing objects: 100% (95/95), 8.66 MiB | 606.00 KiB/s, done.
Total 95 (delta 31), reused 0 (delta 0)

-----> Java app detected
-----> Installing OpenJDK... done
-----> Installing Maven... done
-----> Installing settings.xml... done
-----> Executing: mvn -B -DskipTests=true clean install

       [INFO] Scanning for projects...
       Downloading: https://repo.spring.io/...
       Downloaded: https://repo.spring.io/... (818 B at 1.8 KB/sec)
        ....
       Downloaded: https://s3pository.heroku.com/jvm/... (152 KB at 595.3 KB/sec)
       [INFO] Installing /tmp/build_0c35a5d2-a067-4abc-a232-14b1fb7a8229/target/...
       [INFO] Installing /tmp/build_0c35a5d2-a067-4abc-a232-14b1fb7a8229/pom.xml ...
       [INFO] ------------------------------------------------------------------------
       [INFO] BUILD SUCCESS
       [INFO] ------------------------------------------------------------------------
       [INFO] Total time: 59.358s
       [INFO] Finished at: Fri Mar 07 07:28:25 UTC 2014
       [INFO] Final Memory: 20M/493M
       [INFO] ------------------------------------------------------------------------

-----> Discovering process types
       Procfile declares types -> web

-----> Compressing... done, 70.4MB
-----> Launching... done, v6
       https://agile-sierra-1405.herokuapp.com/ deployed to Heroku

To git@heroku.com:agile-sierra-1405.git
 * [new branch]      main -> main

现在,你的应用程序应该在 Heroku 上启动并运行了。

OpenShift

OpenShift 提供了许多资源,描述了如何部署 Spring Boot 应用程序,包括:

  • 使用 S2I 构建器
  • 架构指南
  • 在 Wildfly 上作为传统 Web 应用程序运行
  • OpenShift Commons Briefing

亚马逊网络服务 (Amazon Web Services, AWS)

AWS提供了多种安装基于 Spring Boot 的应用程序的方式,既可作为传统的 Web 应用程序(war),也可作为带有嵌入式 Web 服务器的可执行 jar 文件。选项包括:

  • AWS Elastic Beanstalk
  • AWS Code Deploy
  • AWS OPS Works
  • AWS Cloud Formation
  • AWS Container Registry

每种方式都有不同的功能和定价模型。在本文档中,我们将介绍使用 AWS Elastic Beanstalk 的方法。

AWS Elastic Beanstalk

正如官方 Elastic Beanstalk Java 指南所述,部署 Java 应用程序主要有两种选择。可以使用“Tomcat 平台”或“Java SE 平台”。

使用 Tomcat 平台

此选项适用于生成 war 文件的 Spring Boot 项目。无需进行特殊配置,只需遵循官方指南即可。

使用 Java SE 平台

此选项适用于生成 jar 文件并运行嵌入式 Web 容器的 Spring Boot 项目。Elastic Beanstalk 环境在端口 80 上运行一个 nginx 实例,以代理在端口 5000 上运行的实际应用程序。要配置它,请将以下行添加到 application.properties 文件中:

server.port=5000

提示:
上传二进制文件而不是源代码

默认情况下,Elastic Beanstalk 会上传源代码并在 AWS 中进行编译。但是,最好上传二进制文件。为此,请将类似于以下内容的行添加到 .elasticbeanstalk/config.yml 文件中:

deploy:
    artifact: target/demo-0.0.1-SNAPSHOT.jar

提示
通过设置环境类型来降低成本

默认情况下,Elastic Beanstalk 环境是负载均衡的。负载均衡器会产生相当大的成本。为避免这种成本,请按照亚马逊文档所述将环境类型设置为“Single instance”。还可以使用 CLI 和以下命令创建单个实例环境:

eb create -s

总结

这是进入 AWS 的最简单方法之一,但还有更多内容需要涵盖,例如如何将 Elastic Beanstalk 集成到任何 CI/CD 工具中,使用 Elastic Beanstalk Maven 插件而不是 CLI 等。

CloudCaptain与亚马逊网络服务 (Amazon Web Services, AWS)

CloudCaptain 通过将你的 Spring Boot 可执行 jar 或 war 文件转换为可在 VirtualBox 或 AWS 上部署的不变最小虚拟机镜像来工作。CloudCaptain 深度集成了 Spring Boot,并使用来自你的 Spring Boot 配置文件的信息来自动配置端口和健康检查 URL。CloudCaptain 利用这些信息来生成镜像,并为它提供的所有资源(实例、安全组、弹性负载均衡器等)进行配置。

一旦你创建了 CloudCaptain 账户,将其与你的 AWS 账户连接,安装了最新版本的 CloudCaptain 客户端,并确保应用程序已由 Maven 或 Gradle 构建(例如,使用 mvn clean package),就可以使用类似以下命令将 Spring Boot 应用程序部署到 AWS:

$ boxfuse run myapp-1.0.jar -env=prod

提示:默认情况下,CloudCaptain 在启动时激活名为 boxfuse 的 Spring profile 。如果你的可执行 jar 或 war 文件包含 application-boxfuse.properties 文件,CloudCaptain 将根据其包含的属性进行配置。

此时,CloudCaptain 将为你的应用程序创建一个镜像,上传它,并在 AWS 上配置和启动必要的资源,结果类似于以下示例输出:

Fusing Image for myapp-1.0.jar ...
Image fused in 00:06.838s (53937 K) -> axelfontaine/myapp:1.0
Creating axelfontaine/myapp ...
Pushing axelfontaine/myapp:1.0 ...
Verifying axelfontaine/myapp:1.0 ...
Creating Elastic IP ...
Mapping myapp-axelfontaine.boxfuse.io to 52.28.233.167 ...
Waiting for AWS to create an AMI for axelfontaine/myapp:1.0 in eu-central-1 (this may take up to 50 seconds) ...
AMI created in 00:23.557s -> ami-d23f38cf
Creating security group boxfuse-sg_axelfontaine/myapp:1.0 ...
Launching t2.micro instance of axelfontaine/myapp:1.0 (ami-d23f38cf) in eu-central-1 ...
Instance launched in 00:30.306s -> i-92ef9f53
Waiting for AWS to boot Instance i-92ef9f53 and Payload to start at https://52.28.235.61/ ...
Payload started in 00:29.266s -> https://52.28.235.61/
Remapping Elastic IP 52.28.233.167 to i-92ef9f53 ...
Waiting 15s for AWS to complete Elastic IP Zero Downtime transition ...
Deployment completed successfully. axelfontaine/myapp:1.0 is up and running at https://myapp-axelfontaine.boxfuse.io/

此时,你的应用程序应该已在 AWS 上启动并运行。

Google Cloud

Google Cloud提供了多种可用于启动 Spring Boot 应用程序的选项。最容易上手的可能是 App Engine,但还可以找到在 Container Engine 中使用容器运行 Spring Boot 或在 Compute Engine 的虚拟机上运行 Spring Boot 的方法。

或者,App Engine Flex 要求你创建一个 app.yaml 文件来描述你的应用程序所需的资源。通常,将此文件放在 src/main/appengine 中,它应该类似于以下文件:

service: "default"

runtime: "java17"
env: "flex"

handlers:
- url: "/.*"
  script: "this field is required, but ignored"

manual_scaling:
  instances: 1

health_check:
  enable_health_check: false

env_variables:
  ENCRYPT_KEY: "your_encryption_key_here"

可以通过将项目 ID 添加到构建配置中来部署应用程序(例如,使用 Maven 插件),如下所示:

<plugin>
    <groupId>com.google.cloud.tools</groupId>
    <artifactId>appengine-maven-plugin</artifactId>
    <version>2.4.4</version>
    <configuration>
        <project>myproject</project>
    </configuration>
</plugin>

然后使用 mvn appengine:deploy 进行部署(需要先进行身份验证,否则构建将失败)。

安装 Spring Boot 应用程序

除了直接使用 java -jar 运行 Spring Boot 应用程序外,还可以将它们作为 systemdinit.d 或 Windows 服务运行。

作为 systemd 服务安装

systemd 是 System V init 系统的继任者,现在被许多现代 Linux 发行版使用。可以使用 systemd “service” 脚本来启动 Spring Boot 应用程序。

假设你已经将 Spring Boot 应用程序打包为位于 /var/myapp 的单个 jar 文件,要将其安装为 systemd 服务,请创建一个名为 myapp.service 的脚本,并将其放置在 /etc/systemd/system 目录中。以下脚本提供了一个示例:

[Unit]
Description=myapp
After=syslog.target network.target

[Service]
User=myapp
Group=myapp

Environment="JAVA_HOME=/path/to/java/home"

ExecStart=${JAVA_HOME}/bin/java -jar /var/myapp/myapp.jar
ExecStop=/bin/kill -15 $MAINPID
SuccessExitStatus=143

[Install]
WantedBy=multi-user.target

提醒:请记住为你的应用程序更改 DescriptionUserGroupEnvironmentExecStart 字段。

注意ExecStart 字段没有声明脚本操作命令,这意味着将默认使用 run 命令。

运行应用程序的用户、PID 文件和控制台日志文件都由 systemd 自身管理,因此必须使用“service”脚本中的适当字段进行配置。

要在系统启动时自动标记应用程序启动,请使用以下命令:

$ systemctl enable myapp.service

作为 init.d 服务(System V)的安装

要将你的应用程序用作 init.d 服务,请配置其构建以生成完全可执行的 jar。

注意:完全可执行的 jar 文件通过在文件前面嵌入一个额外的脚本来实现其功能。目前,某些工具不接受这种格式,因此你可能无法始终使用此技术。例如,jar -xf 可能会静默失败,无法提取已配置为完全可执行的 jar 或 war 文件。因此,建议你仅在打算直接执行 jar 或 war 文件,而不是使用 java -jar 命令运行或将其部署到 servlet 容器中时,才将其配置为完全可执行。

注意:zip64 格式的 jar 文件无法被配置为完全可执行。尝试这样做将导致 jar 文件在执行时或在使用 java -jar 命令时被报告为损坏。包含一个或多个 zip64 格式嵌套 jar 的标准格式 jar 文件可以被配置为完全可执行。

要使用 Maven 创建一个“完全可执行”的 jar,请使用以下插件配置:

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <configuration>
        <executable>true</executable>
    </configuration>
</plugin>

以下示例显示了等效的 Gradle 配置:

tasks.named('bootJar') {
    launchScript()
}

然后,可以通过创建指向 init.d 的符号链接来支持标准的启动、停止、重启和状态命令。

添加到完全可执行的 jar 中的默认启动脚本支持大多数 Linux 发行版,并在 CentOS 和 Ubuntu 上进行了测试。其它平台,如 OS X 和 FreeBSD,需要使用自定义脚本。默认脚本支持以下功能:

  • 以拥有 jar 文件的用户身份启动服务
  • 通过使用 /var/run/<appname>/<appname>.pid 跟踪应用程序的 PID
  • 将控制台日志写入 /var/log/<appname>.log

假设你已经将 Spring Boot 应用程序安装在 /var/myapp 中,要将 Spring Boot 应用程序安装为 init.d 服务,请创建以下符号链接:

$ sudo ln -s /var/myapp/myapp.jar /etc/init.d/myapp

安装完成后,可以以常规方式启动和停止服务。例如,在基于 Debian 的系统上,可以使用以下命令启动服务:

$ service myapp start

提示:如果应用程序启动失败,请检查写入到 /var/log/<appname>.log 的日志文件以查找错误。

还可以使用标准的操作系统工具将应用程序标记为自动启动。例如,在 Debian 上,可以使用以下命令:

$ update-rc.d myapp defaults <priority>

保护 init.d 服务

以下是一套关于如何保护作为 init.d 服务运行的 Spring Boot 应用程序的指导原则。

当以 root 用户身份执行时(例如在以 root 用户身份启动 init.d 服务时),默认的可执行脚本将应用程序作为 RUN_AS_USER 环境变量中指定的用户运行。如果未设置该环境变量,则使用拥有 jar 文件的用户。不应该以 root 用户身份运行 Spring Boot 应用程序,因此 RUN_AS_USER 不应该是 root,并且你的应用程序的 jar 文件也不应该由 root 拥有。相反,应该创建一个特定用户来运行你的应用程序,并设置 RUN_AS_USER 环境变量,或者使用 chown 命令使其成为 jar 文件的所有者,如下所示:

$ chown bootapp:bootapp your-app.jar

在这种情况下,默认的可执行脚本将应用程序作为 bootapp 用户运行。

提示:为了降低应用程序的用户帐户被攻陷的风险,应该考虑阻止其使用登录 shell。例如,可以将该帐户的 shell 设置为 /usr/sbin/nologin

还应该采取措施防止修改应用程序的 jar 文件。首先,配置其权限,使其无法被写入,并且只能由其所有者读取或执行,如下所示:

$ chmod 500 your-app.jar

其次,还应该采取措施限制在应用程序或其运行帐户被攻陷时造成的损害。如果攻击者确实获得了访问权限,他们可能会使 jar 文件可写并更改其内容。防止这种情况的一种方法是通过使用 chattr 使其不可变,如下所示:

$ sudo chattr +i your-app.jar

这将阻止任何用户(包括 root 用户)修改 jar 文件。

如果使用 root 用户来控制应用程序的服务,并且你使用 .conf 文件来定制其启动,那么 .conf 文件将由 root 用户读取和评估。因此,应该相应地保护它。使用 chmod 命令使文件只能由其所有者读取,并使用 chown 命令将 root 设置为所有者,如下所示:

$ chmod 400 your-app.conf
$ sudo chown root:root your-app.conf

自定义启动脚本

Maven 或 Gradle 插件编写的默认嵌入式启动脚本可以以多种方式进行自定义。对于大多数人来说,使用默认脚本加上一些自定义通常就足够了。如果发现自己无法自定义所需的内容,请使用 embeddedLaunchScript 选项完全编写自己的文件。

在编写时自定义启动脚本

在将启动脚本写入 jar 文件时,通常可以自定义脚本的某些元素。例如,init.d 脚本可以提供“描述”。由于你事先知道描述(并且它不需要更改),因此可以在生成 jar 文件时提供它。

要自定义编写的元素,请使用 Spring Boot Maven 插件的 embeddedLaunchScriptProperties 选项或 Spring Boot Gradle 插件的 launchScript 的 properties 属性。

默认脚本支持以下属性替换:
在这里插入图片描述
在这里插入图片描述

运行时自定义脚本

对于需要在写入 jar 文件后自定义的脚本项,可以使用环境变量或配置文件。

默认脚本支持以下环境属性:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

注意PID_FOLDERLOG_FOLDERLOG_FILENAME 变量仅对 init.d 服务有效。对于 systemd,通过使用“service”脚本进行等效的自定义。

除了 JARFILEAPP_NAME 之外,上一节中列出的设置可以使用 .conf 文件进行配置。该文件应位于 jar 文件旁边,并且具有相同的名称,但后缀为 .conf 而不是 .jar。例如,名为 /var/myapp/myapp.jar 的 jar 文件使用名为 /var/myapp/myapp.conf 的配置文件,如下所示:

myapp.conf

JAVA_OPTS=-Xmx1024M
LOG_FOLDER=/custom/log/folder

提示:如果不希望将配置文件放在 jar 文件旁边,可以设置 CONF_FOLDER 环境变量来自定义配置文件的位置。

Microsoft Windows 服务

Spring Boot 应用程序可以使用 winsw 作为 Windows 服务启动。

高效的部署

解压可执行 JAR 文件

如果你从容器中运行应用程序,则可以使用可执行 jar,但通常将其解压并以不同方式运行也很有优势。某些 PaaS 实现还可能会选择在运行之前解压归档文件。例如,Cloud Foundry 就是以这种方式运行的。运行解压归档文件的一种方法是启动适当的启动器,如下所示:

$ jar -xf myapp.jar
$ java org.springframework.boot.loader.launch.JarLauncher

实际上,这比从未解压的归档文件中运行稍微快一些(具体取决于 jar 的大小)。启动后,你不应期望有任何差异。

一旦解压了 jar 文件,还可以通过使用其“自然的” main 方法而不是 JarLauncher 来运行应用程序,从而为启动时间带来额外的提升。例如:

$ jar -xf myapp.jar
$ java -cp "BOOT-INF/classes:BOOT-INF/lib/*" com.example.MyApplication

注意:与应用程序的主方法相比,使用 JarLauncher 具有可预测的类路径顺序的额外好处。jar 包含一个 classpath.idx 文件,该文件在构建类路径时由 JarLauncher 使用。

使用 JVM 进行提前处理(Ahead-of-time Processing)

使用 AOT 生成的初始化代码运行应用程序对启动时间有益。首先,需要确保正在构建的 jar 包括 AOT 生成的代码。

对于 Maven,这意味着应该使用 -Pnative 进行构建以激活 native profile:

$ mvn -Pnative package

对于 Gradle,需要确保你的构建包含 org.springframework.boot.aot 插件。

当 JAR 文件构建完成后,使用将 spring.aot.enabled 系统属性设置为 true 的方式运行它。例如:

$ java -Dspring.aot.enabled=true -jar myapplication.jar

........ Starting AOT-processed MyApplication ...

请注意,使用提前处理也有缺点。它意味着以下限制:

  • 类路径在构建时就已经固定并完全定义
  • 你的应用程序中定义的 bean 不能在运行时更改,这意味着:

1)Spring @Profile 注解和特定于profile的配置具有局限性。

2)如果创建 bean,则不支持更改的属性(例如,@ConditionalOnProperty.enable 属性)。

JVM 的检查点和恢复

协调恢复检查点(Coordinated Restore at Checkpoint:CRaC)是一个 OpenJDK 项目,它定义了一个新的 Java API,允许你在 HotSpot JVM 上对应用程序进行检查点和恢复。它基于 CRIU,一个在 Linux 上实现检查点/恢复功能的项目。

原理如下:你几乎像平常一样启动应用程序,但使用启用了 CRaC 的 JDK 版本,如 Bellsoft Liberica JDK with CRaC 或 Azul Zulu JDK with CRaC。然后,在某个时刻,可能是在执行所有常见代码路径以优化 JVM 性能的一些工作负载之后,你使用 API 调用、jcmd 命令、HTTP 端点或不同机制触发检查点。

然后,将正在运行的 JVM(包括其预热状态)的内存表示序列化到磁盘,以便稍后在另一台具有类似操作系统和 CPU 架构的机器上快速恢复。恢复后的进程保留了 HotSpot JVM 的所有功能,包括运行时的进一步 JIT 优化。

基于 Spring Framework 提供的基础,Spring Boot 提供了对应用程序的检查点和恢复的支持,并在有限范围内开箱即用地管理了诸如套接字、文件和线程池等资源的生命周期。对于其它依赖项以及可能处理这些资源的应用程序代码,预计需要进行额外的生命周期管理。

  • 13
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值