Spring Boot的灵活打包选项在部署应用程序时提供了很多选择。您可以将Spring Boot应用程序部署到各种云平台,虚拟/实际机器,或者使它们在Unix系统上完全可执行。

本节涵盖了一些常见的部署场景。

1. 部署到云端

Spring Boot的可执行jar包已经为大多数流行的云PaaS(平台即服务)提供商准备好了。这些提供商通常要求您“自带容器”。它们管理应用程序进程(不是特定的Java应用程序),因此它们需要一个中间层,将您的应用程序适配到对运行进程的概念。

两个流行的云提供商,Heroku和Cloud Foundry,采用了“构建包”方法。构建包将您部署的代码包装在所需的内容中,以启动您的应用程序。它可能是一个JDK和一个调用java,一个嵌入式Web服务器,或者一个完整的应用服务器。构建包是可插拔的,但理想情况下,您应该尽量减少对其的定制。这减少了不受您控制的功能的占用空间。它最小化了开发和生产环境之间的差异。

理想情况下,您的应用程序,就像一个Spring Boot可执行jar包一样,已经将运行所需的一切打包在其中。

在本节中,我们将看看如何将在“入门”部分中开发的应用程序在云中运行起来。

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

$ 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/找到它。

1.1.1. 绑定服务

默认情况下,有关运行应用程序的元数据以及服务连接信息会作为环境变量(例如:$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");
    }

    // ...

}
Kotlin
import org.springframework.context.EnvironmentAware
import org.springframework.core.env.Environment
import org.springframework.stereotype.Component

@Component
class MyBean : EnvironmentAware {

    private var instanceId: String? = null

    override fun setEnvironment(environment: Environment) {
        instanceId = environment.getProperty("vcap.application.instance_id")
    }

    // ...

}

所有Cloud Foundry属性都以vcap为前缀。您可以使用vcap属性访问应用程序信息(例如应用程序的公共URL)和服务信息(例如数据库凭据)。查看完整详情,请参阅CloudFoundryVcapEnvironmentPostProcessor的Javadoc。

对于配置DataSource等任务,Java CFEnv项目更适合。

1.2. Kubernetes

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

Spring Boot帮助您管理应用程序的状态并使用Actuator导出HTTP Kubernetes探针。

1.2.1. Kubernetes容器生命周期

当Kubernetes删除应用程序实例时,关闭过程涉及多个子系统同时运行:关闭挂钩、注销服务、从负载均衡器中删除实例等。由于此关闭处理是并行进行的(并且由于分布式系统的性质),在此期间可能会将流量路由到已经开始关闭处理的Pod中。

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

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选项来增加终止优雅期。

1.3. Heroku

Heroku是另一个流行的PaaS平台。要自定义Heroku构建,您需要提供一个Procfile,其中包含部署应用程序所需的命令。Heroku为Java应用程序分配一个port,然后确保路由到外部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实例,然后在启动时使用该端口。Heroku PaaS通过$PORT环境变量分配给我们。

这应该是您所需的一切。Heroku部署的最常见工作流程是将代码git push到生产环境,如下例所示:

$ git push heroku main

这将导致以下结果:

初始化存储库,完成。
计算对象:95,完成。
使用多达8个线程进行增量压缩。
压缩对象:100%(78/78),完成。
写入对象:100%(95/95),8.66 MiB | 606.00 KiB/s,完成。
总共95(增量31),重用0(增量0)

-----> 检测到Java应用程序
-----> 安装OpenJDK... 完成
-----> 安装Maven... 完成
-----> 安装settings.xml... 完成
-----> 执行:mvn -B -DskipTests=true clean install

       [INFO] 正在扫描项目...
       下载中:https://repo.spring.io/...
       已下载:https://repo.spring.io/...(1.8 KB/sec)
        ....
       已下载:https://s3pository.heroku.com/jvm/...(595.3 KB/sec)
       [INFO] 安装 /tmp/build_0c35a5d2-a067-4abc-a232-14b1fb7a8229/target/...
       [INFO] 安装 /tmp/build_0c35a5d2-a067-4abc-a232-14b1fb7a8229/pom.xml ...
       [INFO] ------------------------------------------------------------------------
       [INFO] 构建成功
       [INFO] ------------------------------------------------------------------------
       [INFO] 总时间:59.358秒
       [INFO] 完成于:Fri Mar 07 07:28:25 UTC 2014
       [INFO] 最终内存:20M/493M
       [INFO] ------------------------------------------------------------------------

-----> 发现进程类型
       Procfile声明类型 -> web

-----> 压缩... 完成,70.4MB
-----> 启动... 完成,v6
       https://agile-sierra-1405.herokuapp.com/ 部署到Heroku

To [email protected]:agile-sierra-1405.git
 * [new branch]      main -> main

您的应用程序现在应该在Heroku上运行。有关更多详细信息,请参阅将Spring Boot应用程序部署到Heroku

1.4. OpenShift

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

1.5. 亚马逊云服务(AWS)

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

  • AWS弹性Beanstalk

  • AWS代码部署

  • AWS OPS Works

  • AWS云形成

  • AWS容器注册表

每种方式都有不同的功能和定价模型。在本文档中,我们描述了使用AWS弹性Beanstalk的方法。

1.5.1. AWS弹性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环境是负载均衡的。负载均衡器具有显著的成本。为了避免这种成本,请将环境类型设置为“单实例”,如亚马逊文档中所述。您还可以使用CLI创建单实例环境,使用以下命令:

eb create -s

1.5.2. 总结

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

1.6. CloudCaptain和亚马逊云服务

CloudCaptain通过将您的Spring Boot可执行jar或war转换为最小的VM映像,可以在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

查看boxfuse run文档以获取更多选项。如果当前目录中存在boxfuse.conf文件,则会考虑该文件。

默认情况下,CloudCaptain在启动时会激活名为boxfuse的Spring配置文件。如果您的可执行jar或war包含一个application-boxfuse.properties文件,CloudCaptain将基于其中包含的属性进行配置。

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

为myapp-1.0.jar创建映像...
映像在00:06.838秒内合并(53937 K) -> axelfontaine/myapp:1.0
创建axelfontaine/myapp...
推送axelfontaine/myapp:1.0...
验证axelfontaine/myapp:1.0...
创建弹性IP...
将myapp-axelfontaine.boxfuse.io映射到52.28.233.167...
等待AWS在eu-central-1为axelfontaine/myapp:1.0创建AMI(可能需要长达50秒)...
AMI在00:23.557秒内创建 -> ami-d23f38cf
创建安全组boxfuse-sg_axelfontaine/myapp:1.0...
在eu-central-1启动axelfontaine/myapp:1.0的t2.micro实例(ami-d23f38cf)...
实例在00:30.306秒内启动 -> i-92ef9f53
等待AWS启动实例i-92ef9f53和Payload以在https://52.28.235.61/上启动...
Payload在00:29.266秒内启动 -> https://52.28.235.61/
将弹性IP 52.28.233.167重新映射到i-92ef9f53...
等待AWS完成弹性IP零停机过渡15秒...
部署成功完成。axelfontaine/myapp:1.0已在https://myapp-axelfontaine.boxfuse.io/上运行

您的应用程序现在应该在AWS上运行。

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

1.7. Azure

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

1.8. 谷歌云

谷歌云有几种选项可用于启动Spring Boot应用程序。最简单的入门方式可能是使用App Engine,但您也可以找到在Container Engine中运行Spring Boot的容器或在Compute Engine上运行的虚拟机的方法。

要将您的第一个应用程序部署到App Engine标准环境,请按照此教程进行操作。

另外,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进行部署(您需要先进行身份验证,否则构建将失败)。

2. 安装Spring Boot 应用程序

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

2.1. 安装为systemd服务

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

假设您有一个打包为超级jar的Spring Boot应用程序在/var/myapp,要将其安装为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”脚本中的适当字段进行配置。有关更多详细信息,请参阅service unit configuration man page

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

$ systemctl enable myapp.service

运行man systemctl以获取更多详细信息。

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

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

完全可执行的jar通过在文件前面嵌入额外的脚本来工作。目前,一些工具不接受这种格式,因此您可能无法始终使用这种技术。例如,jar -xf可能会在尝试提取已被制作为完全可执行的jar或war时静默失败。建议仅在打算直接执行它时,而不是使用java -jar运行它或部署到servlet容器时,使您的jar或war完全可执行。
zip64格式的jar文件无法制作为完全可执行。尝试这样做将导致在直接执行或使用java -jar时报告为损坏的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以支持标准的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服务,请创建符号链接,如下所示:

$ 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>

2.2.1. 安全化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

2.2.2. 自定义启动脚本

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

在编写启动脚本时进行自定义

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

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

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

名称 描述 Gradle默认值 Maven默认值

mode

脚本模式。

auto

auto

运行时自定义脚本

对于需要在jar文件编写完成后进行自定义的脚本部分,您可以使用环境变量或配置文件

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

变量 描述

MODE

操作模式。默认取决于jar文件的构建方式,但通常为auto(表示它会尝试猜测是否为init脚本,通过检查是否为位于名为init.d目录中的符号链接)。您可以显式设置为service,以便stop|start|status|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文件相同的文件夹)。

LOG_FILENAME

LOG_FOLDER中的日志文件名称(默认为<appname>.log)。

APP_NAME

应用程序的名称。如果jar文件是从符号链接运行的,则脚本会猜测应用程序名称。如果不是符号链接或者您想要显式设置应用程序名称,则这可能很有用。

RUN_ARGS

传递给程序(Spring Boot应用程序)的参数。

JAVA_HOME

通过默认使用PATH来发现java可执行文件的位置,但如果在$JAVA_HOME/bin/java处有可执行文件,则可以显式设置它。

JAVA_OPTS

启动时传递给JVM的选项。

JARFILE

jar文件的显式位置,以防脚本用于启动实际未嵌入的jar文件。

DEBUG

如果不为空,则在shell进程上设置-x标志,允许您查看脚本中的逻辑。

STOP_WAIT_TIME

在强制关闭应用程序之前等待的时间(默认为60秒)。

仅对于init.d服务,PID_FOLDERLOG_FOLDERLOG_FILENAME变量有效。对于systemd,使用“service”脚本进行等效自定义。有关更多详细信息,请参阅service unit configuration man page
使用配置文件

除了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环境变量以自定义配置文件的位置。

要了解如何适当地保护此文件,请参阅保护init.d服务的准则

2.3. Microsoft Windows 服务

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

一个(单独维护的示例)描述了如何为 Spring Boot 应用程序创建 Windows 服务的逐步过程。

3. 高效部署

3.1. 解压可执行的JAR文件

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

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

实际上,与从未解压的存档运行相比,这在启动时稍微更快(取决于jar文件的大小)。启动后,您不应该期望有任何区别。

一旦您解压了jar文件,您还可以通过使用其“自然”主方法而不是 JarLauncher 来加快启动时间。例如:

$ jar -xf myapp.jar
$ java -cp "BOOT-INF/classes:BOOT-INF/lib/*" com.example.MyApplication
使用 JarLauncher 而不是应用程序的主方法具有可预测的类路径顺序的附加好处。jar文件包含一个 classpath.idx 文件,JarLauncher 在构建类路径时使用它。

3.2. 使用JVM的预先处理

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

对于Maven,这意味着您应该使用 -Pnative 进行构建以激活 native 配置文件:

$ mvn -Pnative package

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

构建JAR文件后,使用设置为 truespring.aot.enabled 系统属性运行它。例如:

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

........ 启动 AOT 处理的 MyApplication ...

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

  • 类路径在构建时是固定和完全定义的

  • 应用程序中定义的 bean 不能在运行时更改,这意味着:

    • Spring 的 @Profile 注解和特定配置 有限制

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

要了解更多关于预先处理的信息,请参阅 理解 Spring 预先处理部分

3.3. 使用JVM的检查点和恢复

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

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

运行中的 JVM 的内存表示,包括其热度,然后被序列化到磁盘,允许在以后的某个时间点快速恢复,可能在具有类似操作系统和 CPU 架构的另一台机器上。恢复的进程保留 HotSpot JVM 的所有功能,包括运行时的进一步 JIT 优化。

基于 Spring Framework 提供的基础,Spring Boot 提供了对检查点和恢复应用程序的支持,并且默认管理资源的生命周期,如套接字、文件和线程池 在有限范围内。对于其他依赖项和可能处理这些资源的应用程序代码,预计会有额外的生命周期管理。

您可以在 Spring Framework JVM 检查点还原支持文档 中找到有关支持的两种模式(“按需检查点/恢复运行中的应用程序”和“启动时自动检查点/恢复”)、如何启用检查点和恢复支持以及一些指南的更多详细信息。

4. 接下来阅读什么

请查看 Cloud FoundryHerokuOpenShiftBoxfuse 网站,了解有关 PaaS 可提供的功能类型的更多信息。这只是四个最受欢迎的 Java PaaS 提供商之一。由于 Spring Boot 非常适合基于云的部署,您也可以自由考虑其他提供商。

接下来的部分将继续介绍 GraalVM Native Images,或者您可以直接阅读关于 Spring Boot CLI 或我们的 构建工具插件 的内容。