如何在Linux系统中将Spring Boot应用程序打包为可执行jar as a Service ?这是推荐的方法吗,还是应该将这个应用程序转换为war并将其安装到Tomcat中?

目前,我可以从屏幕会话运行Spring引导应用程序,这很好,但需要在服务器重新启动后手动启动。

我正在寻找的是一般的建议/方向或样本init。D脚本,如果我的方法与可执行jar是适当的。


当前回答

我试图使springboot应用程序呈现为“init”。D”风格的shell脚本与压缩Java应用程序钉在最后

通过符号链接这些脚本从/etc/init.D /spring-app到/opt/spring-app.jar,并chmod jar使其可执行。D /spring-app启动/etc/init。D /spring-app stop”和其他可能的状态工作

假设是init。来自springboot的d风格脚本看起来他们有必要的魔法字符串(像# Default-Start: 2 3 4 5) chkconfig将能够将其作为“服务”添加。

但是我想让它和systemd一起工作

为了做到这一点,我尝试了上面其他答案中的许多食谱,但在Centos 7.2和Springboot 1.3上,它们都不适合我。大多数情况下,它们会启动服务,但无法跟踪pid

最后,我发现下面的方法对我有用,当/etc/init.D链接也到位了。一个类似于下面的文件应该安装为/usr/lib/systemd/system/spring-app.service

[Unit]
Description=My loverly application
After=syslog.target 

[Service]
Type=forking
PIDFile=/var/run/spring-app/spring-app.pid
ExecStart=/etc/init.d/spring-app start
SuccessExitStatus=143

[Install]
WantedBy=multi-user.target

其他回答

我自己刚刚抽出时间来做这件事,所以下面是到目前为止我在CentOS初始化方面的进展。D业务控制器脚本。到目前为止,它工作得很好,但我不是leet Bash黑客,所以我相信还有改进的空间,所以欢迎提出改进的想法。

首先,我为每个服务准备了一个简短的配置脚本/data/svcmgmt/conf/my-spring-boot-api.sh,用于设置环境变量。

#!/bin/bash
export JAVA_HOME=/opt/jdk1.8.0_05/jre
export APP_HOME=/data/apps/my-spring-boot-api
export APP_NAME=my-spring-boot-api
export APP_PORT=40001

我使用CentOS,所以为了确保我的服务在服务器重启后启动,我在/etc/init.d/my-spring-boot-api中有一个服务控制脚本:

#!/bin/bash
# description: my-spring-boot-api start stop restart
# processname: my-spring-boot-api
# chkconfig: 234 20 80

. /data/svcmgmt/conf/my-spring-boot-api.sh

/data/svcmgmt/bin/spring-boot-service.sh $1

exit 0

如您所见,它调用初始配置脚本来设置环境变量,然后调用我用来重新启动所有Spring Boot服务的共享脚本。共享脚本是所有内容的核心所在:

#!/bin/bash

echo "Service [$APP_NAME] - [$1]"

echo "    JAVA_HOME=$JAVA_HOME"
echo "    APP_HOME=$APP_HOME"
echo "    APP_NAME=$APP_NAME"
echo "    APP_PORT=$APP_PORT"

function start {
    if pkill -0 -f $APP_NAME.jar > /dev/null 2>&1
    then
        echo "Service [$APP_NAME] is already running. Ignoring startup request."
        exit 1
    fi
    echo "Starting application..."
    nohup $JAVA_HOME/bin/java -jar $APP_HOME/$APP_NAME.jar \
        --spring.config.location=file:$APP_HOME/config/   \
        < /dev/null > $APP_HOME/logs/app.log 2>&1 &
}

function stop {
    if ! pkill -0 -f $APP_NAME.jar > /dev/null 2>&1
    then
        echo "Service [$APP_NAME] is not running. Ignoring shutdown request."
        exit 1
    fi

    # First, we will try to trigger a controlled shutdown using 
    # spring-boot-actuator
    curl -X POST http://localhost:$APP_PORT/shutdown < /dev/null > /dev/null 2>&1

    # Wait until the server process has shut down
    attempts=0
    while pkill -0 -f $APP_NAME.jar > /dev/null 2>&1
    do
        attempts=$[$attempts + 1]
        if [ $attempts -gt 5 ]
        then
            # We have waited too long. Kill it.
            pkill -f $APP_NAME.jar > /dev/null 2>&1
        fi
        sleep 1s
    done
}

case $1 in
start)
    start
;;
stop)
    stop
;;
restart)
    stop
    start
;;
esac
exit 0

当停止时,它将尝试使用弹簧引导驱动器来执行受控关机。但是,如果没有配置执行器或未能在合理的时间范围内关闭(我给它5秒,这真的有点短),进程将被杀死。

此外,脚本还假设运行应用程序的java进程是进程详细信息文本中唯一带有“my-spring-boot-api.jar”的进程。在我的环境中,这是一个安全的假设,这意味着我不需要跟踪pid。

I don't know of a "standard" shrink-wrapped way to do that with a Java app, but it's definitely a good idea (you want to benefit from the keep-alive and monitoring capabilities of the operating system if they are there). It's on the roadmap to provide something from the Spring Boot tool support (maven and gradle), but for now you are probably going to have to roll your own. The best solution I know of right now is Foreman, which has a declarative approach and one line commands for packaging init scripts for various standard OS formats (monit, sys V, upstart etc.). There is also evidence of people having set stuff up with gradle (e.g. here).

作为Windows服务

如果你想在windows机器上运行,请下载winsw.exe

 http://repo.jenkins-ci.org/releases/com/sun/winsw/winsw/2.1.2/

之后,将其重命名为jar文件名(例如:your-app.jar)

winsw.exe -> your-app.exe

现在创建一个xml文件your-app.xml,并将以下内容复制到该文件中

<?xml version="1.0" encoding="UTF-8"?>
<service>
     <id>your-app</id>
     <name>your-app</name>
     <description>your-app as a Windows Service</description>
     <executable>java</executable>
     <arguments>-jar "your-app.jar"</arguments>
     <logmode>rotate</logmode>
</service>

确保exe和xml以及jar文件在同一个文件夹中。

在此之后,在管理员权限下打开命令提示符并将其安装到windows服务。

your-app.exe install
eg -> D:\Springboot\your-app.exe install

如果失败了

Error: Registry key 'Software\JavaSoft\Java Runtime Environment'\CurrentVersion' has value '1.8', but '1.7' is required.

然后试试下面的方法:

Delete java.exe, javaw.exe and javaws.exe from C:\Windows\System32

就是这样:).

在windows下卸载服务

your-app.exe uninstall

查看/运行/停止服务: win+r并输入Administrative tools,然后从中选择服务。然后右击选择选项-运行/停止

在systemd单元文件中,您可以通过目录或EnvironmentFile设置环境变量。我建议这样做,因为这似乎是最小的摩擦。

示例单元文件

$ cat /etc/systemd/system/hello-world.service
[Unit]
Description=Hello World Service
After=systend-user-sessions.service

[Service]
EnvironmentFile=/etc/sysconfig/hello-world
Type=simple
ExecStart=/usr/bin/java ... hello-world.jar

然后在/etc/sysconfig/hello-world下设置一个文件,其中包含Spring Boot变量的大写名称。例如,一个名为server的变量。port将遵循SERVER_PORT形式作为环境变量:

$ cat /etc/sysconfig/hello-world
SERVER_PORT=8081

这里所利用的机制是Spring Boot应用程序将获取属性列表,然后转换它们,将所有内容都改为大写,并将点替换为下划线。一旦Spring Boot应用程序完成了这个过程,它就会寻找匹配的环境变量,并相应地使用找到的环境变量。

在这篇题为:如何通过环境变量在其名称中设置带有下划线的Spring Boot属性的SO Q&A中强调了更多细节?

参考文献

第四部分。弹簧引导功能- 24。外部化配置

我试图使springboot应用程序呈现为“init”。D”风格的shell脚本与压缩Java应用程序钉在最后

通过符号链接这些脚本从/etc/init.D /spring-app到/opt/spring-app.jar,并chmod jar使其可执行。D /spring-app启动/etc/init。D /spring-app stop”和其他可能的状态工作

假设是init。来自springboot的d风格脚本看起来他们有必要的魔法字符串(像# Default-Start: 2 3 4 5) chkconfig将能够将其作为“服务”添加。

但是我想让它和systemd一起工作

为了做到这一点,我尝试了上面其他答案中的许多食谱,但在Centos 7.2和Springboot 1.3上,它们都不适合我。大多数情况下,它们会启动服务,但无法跟踪pid

最后,我发现下面的方法对我有用,当/etc/init.D链接也到位了。一个类似于下面的文件应该安装为/usr/lib/systemd/system/spring-app.service

[Unit]
Description=My loverly application
After=syslog.target 

[Service]
Type=forking
PIDFile=/var/run/spring-app/spring-app.pid
ExecStart=/etc/init.d/spring-app start
SuccessExitStatus=143

[Install]
WantedBy=multi-user.target