部署 Spring Boot 应用中文文档

本文为官方文档直译版本。原文链接

部署 Spring Boot 应用中文文档

  • 引言
  • 部署到云
  • [安装 Spring Boot 应用程序](#安装 Spring Boot 应用程序)
  • 高效部署
    • [解压可执行 JAR](#解压可执行 JAR)
    • [使用 JVM 提前处理](#使用 JVM 提前处理)
    • [使用 JVM 检查点和还原](#使用 JVM 检查点和还原)

引言

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 命令部署应用程序的过程:

shell 复制代码
$ cf push acloudyspringtime -p target/demo-0.0.1-SNAPSHOT.jar

在前面的示例中,我们将 acloudyspringtime 替换为 cf 作为应用程序名称的任何值。

有关更多选项,请参阅 cf push 文档。如果同一目录中存在 Cloud Foundry manifest.yml 文件,则会考虑该文件。

此时,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 命令验证已部署应用程序的状态,如下例所示:

shell 复制代码
$ 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抽象访问的属性,如下例所示:

java 复制代码
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)和服务信息(如数据库凭据)。有关完整的详细信息,请参阅 CloudFoundryVcapEnvironmentPostProcessor Javadoc

Java CFEnv 项目更适合配置数据源等任务。

Kubernetes

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

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

Kubernetes 容器生命周期

当 Kubernetes 删除应用程序实例时,关机过程会同时涉及多个子系统:关机钩子、取消服务注册、从负载平衡器中移除实例...由于关机处理是并行发生的(而且由于分布式系统的特性),因此存在一个窗口,在此期间,流量可能会被路由到也已开始关机处理的 pod。

您可以在 preStop 处理程序中配置休眠执行,以避免请求被路由到已开始关闭的 pod。睡眠时间应足够长,以便新请求不再被路由到 pod,其持续时间因部署而异。可以使用 pod 配置文件中的 PodSpec 对预停止处理程序进行如下配置:

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

一旦预停止钩子完成,SIGTERM 就会发送到容器,然后开始优雅关机,允许完成任何剩余的处理中请求。

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

Heroku

Heroku 是另一个流行的 PaaS 平台。要定制 Heroku 的构建,您需要提供一个 Procfile,它提供了部署应用程序所需的命令。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 将代码推送到生产环境,如下例所示:

shell 复制代码
$ 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 上运行了。有关详细信息,请参阅将 Spring Boot 应用程序部署到 Heroku

OpenShift

OpenShift 有许多资源介绍如何部署 Spring Boot 应用程序,包括:

亚马逊网络服务(AWS)

Amazon Web Services 提供多种方式来安装基于 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 文件中添加以下一行:

properties 复制代码
server.port=5000

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

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

yaml 复制代码
deploy:
    artifact: target/demo-0.0.1-SNAPSHOT.jar

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

默认情况下,Elastic Beanstalk 环境是负载平衡的。负载平衡器的成本很高。要避免这一成本,可将环境类型设置为 "单实例",如亚马逊文档中所述。你也可以使用 CLI 和以下命令创建单实例环境:

shell 复制代码
eb create -s

总结

这是访问AWS最简单的方法之一,但还有更多内容需要涉及,例如如何将Elastic Beanstalk集成到任何CI/CD工具中,使用Elastic Beanstalk Maven插件而不是CLI等。有一篇博文详细介绍了这些主题。

CloudCaptain 和亚马逊网络服务

CloudCaptain 的工作原理是将您的 Spring Boot 可执行 jar 或 war 转换成最小的虚拟机映像,该映像可在 VirtualBox 或 AWS 上部署,且不会发生变化。CloudCaptain 与 Spring Boot 深度集成,并使用 Spring Boot 配置文件中的信息自动配置端口和健康检查 URL。CloudCaptain 将这些信息用于生成镜像以及提供所有资源(实例、安全组、弹性负载平衡器等)。

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

shell 复制代码
$ boxfuse run myapp-1.0.jar -env=prod

默认情况下,CloudCaptain 会在启动时激活名为 boxfuse 的 Spring 配置文件。如果您的可执行 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 上运行了。

请参阅在 EC2 上部署 Spring Boot 应用程序的博文以及 CloudCaptain Spring Boot 集成的文档,开始使用 Maven 构建运行应用程序。

Azure

入门指南将指导您将 Spring Boot 应用程序部署到 Azure Spring CloudAzure App Service

谷歌云

Google Cloud 有多个可用于启动 Spring Boot 应用程序的选项。最容易上手的可能是 App Engine,但您也可以通过 Container Engine 在容器中运行 Spring Boot,或通过 Compute Engine 在虚拟机上运行 Spring Boot。

要在 App Engine 标准环境中运行您的第一个应用程序,请参考本教程

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

yaml 复制代码
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 插件),如下例所示:

xml 复制代码
<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 发行版所采用。Spring Boot 应用程序可通过 systemd "服务" 脚本启动。

假设你在 /var/myapp 目录中将 Spring Boot 应用程序打包为 uber 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 字段没有声明脚本操作命令,这意味着默认使用运行命令。

运行应用程序的用户、PID 文件和控制台日志文件由 systemd 本身管理,因此必须在 "服务" 脚本中使用相应字段进行配置。详情请查阅服务单元配置手册

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

shell 复制代码
$ systemctl enable myapp.service

运行 man systemctl 了解更多详情。

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

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

完全可执行的 jar 通过在文件前面嵌入一个额外的脚本来工作。目前,有些工具不接受这种格式,所以你可能并不总是能使用这种技术。例如,jar -xf 可能无法解压缩完全可执行的 jar 或 war。建议您只有在打算直接执行 jar 或 war 时才将其设置为完全可执行,而不是使用 java -jar 运行或将其部署到 servlet 容器中。
zip64 格式的 jar 文件无法完全执行。如果尝试这样做,在直接执行或使用 java -jar 执行时,jar 文件将被报告为损坏。包含一个或多个 zip64 格式嵌套 jar 的标准格式 jar 文件可以完全执行。

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

xml 复制代码
<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <configuration>
        <executable>true</executable>
    </configuration>
</plugin>

下面的示例显示了相应的 Gradle 配置:

groovy 复制代码
tasks.named('bootJar') {
    launchScript()
}

然后,可以将其链接到 init.d,以支持标准的startstoprestartstatus命令。

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

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

假设在 /var/myapp 中安装了 Spring Boot 应用程序,要将 Spring Boot 应用程序安装为 init.d 服务,请创建一个符号链接,如下所示:

shell 复制代码
$ sudo ln -s /var/myapp/myapp.jar /etc/init.d/myapp

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

shell 复制代码
$ service myapp start

如果应用程序无法启动,请检查写入 /var/log/<appname>.log 的日志文件是否有错误。

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

shell 复制代码
$ update-rc.d myapp defaults <priority>

init.d 服务安全

以下是一套关于如何确保作为 init.d 服务运行的 Spring Boot 应用程序安全的指南。它并不打算详尽无遗地列出加固应用程序及其运行环境应采取的所有措施。

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

shell 复制代码
$ chown bootapp:bootapp your-app.jar

为降低应用程序用户账户被入侵的几率,应考虑阻止其使用 shell 登录。例如,可以将账户的 shell 设置为 /usr/sbin/nologin

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

shell 复制代码
$ chmod 500 your-app.jar

其次,如果您的应用程序或运行该程序的账户被入侵,您还应采取措施限制损失。如果攻击者确实获得了访问权限,他们可以使 jar 文件可写并更改其内容。防止这种情况的一种方法是使用 chattr 使其不可变,如下例所示:

shell 复制代码
$ sudo chattr +i your-app.jar

这将防止包括 root 用户在内的任何用户修改 jar。

如果使用 root 用户控制应用程序的服务,并使用 .conf 文件自定义启动,则 .conf 文件将由 root 用户读取和评估。因此应确保该文件的安全。如以下示例所示,使用 chmod 使文件只能由所有者读取,并使用 chown 使根用户成为所有者:

shell 复制代码
$ chmod 400 your-app.conf
$ sudo chown root:root your-app.conf

自定义启动脚本

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

自定义已编写的启动脚本

在将启动脚本写入 jar 文件时,自定义启动脚本的元素往往很有意义。例如,init.d 脚本可以提供 "description"。既然你事先知道描述(而且不需要更改),那么不妨在生成 jar 时提供它。

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

默认脚本支持以下属性替换:

属性名称 描述 Gradle 默认值 Maven 默认值
mode 脚本模式。 auto auto
initInfoProvides "INIT INFO"的 Provides 部分 ${task.baseName} ${project.artifactId}
initInfoRequiredStart "INIT INFO"的 Required-Start 部分 $remote_fs $syslog $network $remote_fs $syslog $network
initInfoRequiredStop "INIT INFO"的 Required-Stop 部分 $remote_fs $syslog $network $remote_fs $syslog $network
initInfoDefaultStart "INIT INFO"的 Default-Start 部分 2 3 4 5 2 3 4 5
initInfoDefaultStop "INIT INFO"的 Default-Stop 部分 0 1 6 0 1 6
initInfoShortDescription "INIT INFO"的 Short-Description 部分 ${project.description} 的单行版本(回退至 ${task.baseName} ${project.name}
initInfoDescription "INIT INFO"的 Short-Description 部分 ${project.description} (回退至 ${task.baseName} ${project.description} (回退至 ${project.name}
initInfoChkconfig "INIT INFO"的 chkconfig 部分 2345 99 01 2345 99 01
confFolder 默认值为CONF_FOLDER 包含 jar 的文件夹 包含 jar 的文件夹
inlinedConfScript 默认启动脚本中应内联的文件脚本引用。它可用于在加载任何外部配置文件前设置环境变量(如 JAVA_OPTS)。
logFolder LOG_FOLDER 的默认值。仅对 init.d 服务有效
logFilename LOG_FILENAME 的默认值。仅对 init.d 服务有效
pidFolder PID_FOLDER 的默认值。仅对 init.d 服务有效
pidFilename PID_FOLDER 中 PID 文件名的默认值。仅对 init.d 服务有效
useStartStopDaemon start-stop-daemon进程命令可用时,是否应使用该命令来控制进程 true true
stopWaitTime STOP_WAIT_TIME 的默认值(秒)。仅对 init.d 服务有效 60 60
自定义运行时的脚本

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

默认脚本支持以下环境属性:

变量 描述
MODE 运行 "模式"。默认值取决于 jar 的构建方式,但通常是auto(这意味着它会通过检查它是否是 init.d 目录中的一个符号链接来猜测它是否是一个启动脚本)。你可以明确地将其设置为 service,这样 stop&#124;start&#124;status&#124;restart 命令就能正常工作;如果你想在前台运行脚本,也可以将其设置为 run
RUN_AS_USER 用于运行应用程序的用户。未设置时,将使用拥有 jar 文件的用户。
USE_START_STOP_DAEMON start-stop-daemon进程命令可用时,是否应使用该命令来控制进程。默认为 true
PID_FOLDER pid 文件夹的根名称(默认为 /var/run)。
LOG_FOLDER 存放日志文件的文件夹名称(默认为 /var/log)。
CONF_FOLDER 读取 .conf 文件的文件夹名称(默认情况下与 jar-file 文件夹相同)。
LOG_FILENAME LOG_FOLDER 中日志文件的名称(默认为 <appname>.log)。
APP_NAME 应用程序名称。如果 jar 是通过符号链接运行的,脚本会猜测应用程序的名称。如果它不是一个符号链接,或者你想明确设置应用程序名称,这可能会很有用。
RUN_ARGS 传给程序(Spring Boot 应用程序)的参数。
JAVA_HOME java 可执行文件的位置默认通过 PATH 查找,但如果在 $JAVA_HOME/bin/java 处有可执行文件,则可以明确设置。
JAVA_OPTS 启动 JVM 时传递给它的选项。
JARFILE jar 文件的明确位置,以防脚本被用于启动实际上未嵌入的 jar。
DEBUG 如果不为空,则在 shell 进程中设置 -x 标志,以便查看脚本中的逻辑。
STOP_WAIT_TIME 停止应用程序后强制关闭前的等待时间(默认为 60 秒)。

PID_FOLDERLOG_FOLDERLOG_FILENAME 变量仅对 init.d 服务有效。对于 systemd,可使用 "service" 脚本进行相应的自定义设置。更多详情,请参阅服务单元配置手册

使用 Conf Gile

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

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

如果不喜欢将配置文件放在 jar 文件旁边,可以设置 CONF_FOLDER 环境变量,自定义配置文件的位置。

要了解如何适当保护该文件,请参阅保护 init.d 服务的指南。

Microsoft Windows 服务

可以使用 winsw 将 Spring Boot 应用程序作为 Windows 服务启动。
本文档(单独维护的示例)将逐步介绍如何为 Spring Boot 应用程序创建 Windows 服务。

高效部署

解压可执行 JAR

如果从容器中运行应用程序,可以使用可执行 jar,但将其解压缩并以另一种方式运行通常也有好处。某些 PaaS 实现也可能选择在运行前解压缩存档。例如,Cloud Foundry 就是这样运行的。运行解压缩存档的一种方法是启动相应的启动器,如下所示:

shell 复制代码
$ jar -xf myapp.jar
$ java org.springframework.boot.loader.launch.JarLauncher

实际上,启动时的速度(取决于 jar 的大小)要比从未爆发的压缩包运行时稍快一些。启动后,就不会有任何差别了。

解压缩 jar 文件后,还可以通过使用 "自然" 主方法而不是 JarLauncher 运行应用程序来额外延长启动时间。例如:

shell 复制代码
$ jar -xf myapp.jar
$ java -cp "BOOT-INF/classes:BOOT-INF/lib/*" com.example.MyApplication

在应用程序的主方法上使用 JarLauncher 还有一个好处,那就是类路径顺序可以预测。jar 中包含一个 classpath.idx 文件,JarLauncher 在构建类路径时会使用该文件。

使用 JVM 提前处理

使用 AOT 生成的初始化代码运行应用程序对启动时间非常有利。首先,您需要确保构建的 jar 包含 AOT 生成的代码。

对于 Maven 而言,这意味着您在构建时应使用 -Pnative 激活native配置文件:

shell 复制代码
$ mvn -Pnative package

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

JAR 生成后,运行时将 spring.aot.enabled 系统属性设置为 true。例如

shell 复制代码
$ java -Dspring.aot.enabled=true -jar myapplication.jar

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

要注意的是,使用超前处理有其缺点。它意味着以下限制:

  • 类路径是固定的,在构建时已完全定义
  • 应用程序中定义的Bean类在运行时不会改变,这意味着
    • Spring @Profile 注解和特定于配置文件的配置有其局限性
    • 不支持在创建 Bean 时改变的属性(例如,@ConditionalOnProperty.enable 属性)。

要了解有关超前处理的更多信息,请参阅了解Spring超前处理部分。

使用 JVM 检查点和还原

Coordinated Restore at Checkpoint(CRaC)是一个 OpenJDK 项目,它定义了一个新的 Java API,允许您在 HotSpot JVM 上检查点和还原应用程序。它基于在 Linux 上实现检查点/还原功能的 CRIU 项目。

其原理如下:几乎像往常一样启动应用程序,但使用的是支持 CRaC 的 JDK 版本,如支持 CRaC 的 Bellsoft Liberica JDK支持 CRaC 的 Azul Zulu JDK。然后在某个时间点,可能是在通过执行所有常用代码路径热身 JVM 的某些工作负载之后,使用 API 调用、jcmd 命令、HTTP 端点或其他机制触发检查点。

然后,运行中的 JVM 的内存表示(包括其预热)会被序列化到磁盘上,这样就可以在稍后的时间点快速还原,可能是在另一台具有类似操作系统和 CPU 架构的机器上。恢复后的进程保留了 HotSpot JVM 的所有功能,包括运行时的进一步 JIT 优化。

基于 Spring Framework 提供的基础,Spring Boot 支持检查点和恢复应用程序,并在有限的范围内管理资源(如套接字、文件和线程池)的开箱即用生命周期。预计其他依赖项和处理此类资源的应用程序代码还需要额外的生命周期管理。

有关支持的两种模式("按需检查点/还原运行中的应用程序 "和 "启动时自动检查点/还原")、如何启用检查点和还原支持以及一些指南的更多详情,请参阅 Spring Framework JVM 检查点还原支持文档

相关推荐
向阳121829 分钟前
mybatis 缓存
java·缓存·mybatis
上等猿36 分钟前
函数式编程&Lambda表达式
java
蓝染-惣右介1 小时前
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
java·设计模式
等一场春雨1 小时前
springboot 3 websocket react 系统提示,选手实时数据更新监控
spring boot·websocket·react.js
秋恬意1 小时前
IBatis和MyBatis在细节上的不同有哪些
java·mybatis
荆州克莱2 小时前
Golang的性能监控指标
spring boot·spring·spring cloud·css3·技术
齐 飞2 小时前
BeanFactory和FactoryBean
java·sprint
大霞上仙2 小时前
lxml 解析xml\html
java·服务器·网络
Xiaoweidumpb2 小时前
tomcat temp临时文件不清空,占用硬盘,jdk字体内存泄漏
java·tomcat