Spring Boot 应用程序作为服务

215

如何将打包为可执行jar的Spring Boot应用程序在Linux系统中配置为服务?这种方法是否值得推荐,或者我应该将此应用程序转换为war文件并安装到Tomcat中?

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

我正在寻找一般建议/方向或示例init.d脚本,如果我的使用可执行的jar 是适当的。


开始之前,请问你的发行版使用 upstart 还是 systemd? - yglodt
1
请查看以下链接 https://github.com/rburgst/spring-boot-initscript/blob/master/spring-boot.sh - Dan Torrey
在这里解释了如何将Spring Boot应用程序安装为Linux服务:[https://springhow.com/installing-spring-boot-applications-as-linux-service/] - Raja Anbazhagan
20个回答

155
以下方法适用于springboot 1.3及以上版本: 作为init.d服务 可执行的jar包拥有通常的启动(start)、停止(stop)、重启(restart)和状态(status)命令。默认情况下,它还会在通常的/var/run目录中设置PID文件,并在通常的/var/log目录中记录日志。
你只需要像下面这样将你的jar文件创建符号链接到/etc/init.d目录中即可。
sudo link -s /var/myapp/myapp.jar /etc/init.d/myapp

或者

sudo ln -s ~/myproject/build/libs/myapp-1.0.jar /etc/init.d/myapp_servicename

之后,您可以像往常一样进行操作。

/etc/init.d/myapp start

如果需要,在引导时可以在任何运行级别中设置一个链接以启动/停止应用程序。


作为systemd服务

要运行安装在var/myapp中的Spring Boot应用程序,您可以在/etc/systemd/system/myapp.service中添加以下脚本:

[Unit]
Description=myapp
After=syslog.target

[Service]
ExecStart=/var/myapp/myapp.jar

[Install]
WantedBy=multi-user.target

注意:如果您使用此方法,请不要忘记使jar文件本身可执行(使用chmod +x),否则它将出现“权限被拒绝”的错误。

参考

http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/html/deployment-install.html#deployment-service


2
“完全可执行的JAR”方法是如何工作的?我使用的是CentOS 6.6。我在我的pom.xml中添加了<executable>true</executable>,但打包的JAR文件无法执行(... ./myapp.jar ... cannot execute binary file)。 - Abdull
5
这个答案仅适用于尚未发布的当前1.3里程碑版本。1.1和1.2分支需要查看这里的其他回答。 翻译:此答案仅适用于尚未发布的当前1.3里程碑版本,1.1和1.2分支需要查看其他回答。 - voor
6
大家知道如何将类似于“-Dspring.profiles.active=prod”这样的参数传递给这个服务吗?问题来源 - https://dev59.com/DF0Z5IYBdhLWcg3wnRgA - nKognito
2
我无法停止spring-boot应用程序。 /etc/init.d stop无法停止该应用程序,它正在尝试重新启动它。 - tintin
2
如果您想要监控进程并在其死亡时重新启动它,而不编写系统守护程序,请查看http://patrickgrimard.com/2014/06/06/bootiful-spring-apps-with-supervisor/。 - ruX
显示剩余8条评论

135
以下是在Linux中安装Java应用程序作为系统服务的最简单方法。
这个解决方案使用了systemd,现在任何现代的发行版都会使用它,因此不需要安装任何其他工具或服务。
首先,在/etc/systemd/system目录下创建一个名为javaservice.service的服务文件,内容如下:
[Unit]
Description=Java Service

[Service]
User=nobody
# The configuration file application.properties should be here:
WorkingDirectory=/data 
ExecStart=/usr/bin/java -Xmx256m -jar application.jar --server.port=8081
SuccessExitStatus=143
TimeoutStopSec=10
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

其次,通知systemd有关新的服务文件。
systemctl daemon-reload

并启用它,使其在启动时运行:
systemctl enable javaservice.service

最终,您可以使用以下命令来启动/停止您的新服务:
systemctl start javaservice
systemctl stop javaservice
systemctl restart javaservice
systemctl status javaservice

只要你使用systemd,这是设置Java应用程序作为系统服务的最不侵入和清洁的方式。
我特别喜欢这个解决方案的原因是你不需要安装和配置任何其他软件。预装的systemd会为你完成所有工作,你的服务会像任何其他系统服务一样运行。我已经在各种发行版上使用它进行生产一段时间了,它就像你期望的那样工作。
另一个好处是,通过使用/usr/bin/java,你可以轻松添加jvm参数,比如-Xmx256m。
还可以阅读官方Spring Boot文档中关于systemd部分的内容: http://docs.spring.io/spring-boot/docs/current/reference/html/deployment-install.html

它如何知道如何停止它?记录pid然后杀死它吗? - mist
2
使用Spring Boot 1.3+,您可以生成一个完全可执行的war文件,因此不需要java -jar ...这一步骤,只需在那里使用文件名即可。 - Pierre Henry
2
我更喜欢使用完整的Java命令行,因为这样可以添加JVM参数。 - yglodt
1
对于其他人想知道的,SuccessExitStatus=143 的意思是“将退出状态 143(对应 SIGTERM)视为此服务的正常退出状态”。 - spinlok
3
为了正确的启动顺序,您可能需要在[Unit]部分中添加排序语句,例如 After=mysql.serviceBefore=apache2.service - rustyx
显示剩余4条评论

59

您还可以使用supervisord,这是一个非常方便的守护进程,可用于轻松控制服务。这些服务由简单的配置文件定义,定义了要在哪个用户、哪个目录下执行等信息,有无数的选项。supervisord语法非常简单,因此它是编写SysV init脚本的很好替代品。

以下是一个适用于您正在尝试运行/控制的程序的简单的supervisord配置文件(将其放入/etc/supervisor/conf.d/yourapp.conf中)。

/etc/supervisor/conf.d/yourapp.conf

[program:yourapp]
command=/usr/bin/java -jar /path/to/application.jar
user=usertorun
autostart=true
autorestart=true
startsecs=10
startretries=3
stdout_logfile=/var/log/yourapp-stdout.log
stderr_logfile=/var/log/yourapp-stderr.log

要控制该应用程序,您需要执行supervisorctl命令,这将呈现一个提示符,您可以在其中启动、停止和查看状态yourapp。

CLI

# sudo supervisorctl
yourapp             RUNNING   pid 123123, uptime 1 day, 15:00:00
supervisor> stop yourapp
supervisor> start yourapp
如果supervisord守护程序已经在运行,并且您已经添加了服务的配置而没有重新启动守护程序,您只需在supervisorctl shell中执行rereadupdate命令即可。

这使您拥有使用SysV Init脚本所具有的所有灵活性,但易于使用和控制。请查看文档了解更多信息。

终于有东西可以直接用了,感谢您提供的supervisord提示。 - Vitaly Sazanovich
这个功能与大多数当前的Linux发行版内置的systemd相同。 - rustyx

19
我刚刚自己完成了这个任务,以下是我在CentOS init.d服务控制器脚本方面的进展。目前为止它运行得非常好,但我不是一个熟练的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

当停止时,它将尝试使用Spring Boot Actuator执行受控关闭。然而,如果Actuator未配置或在合理时间内未能关闭(我给了它5秒钟,实际上有点短),则进程将被终止。
此外,脚本假设运行应用程序的Java进程将是唯一一个具有“my-spring-boot-api.jar”文本的进程详细信息。这在我的环境中是安全的假设,这意味着我不需要跟踪PID。

3
无需编写自己的启动/停止脚本。从Spring Boot 1.3版本开始,已提供此功能。请参阅http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#deployment-install了解更多详情。 - gregturn
很高兴知道这是一个选项,但它只是消除了使用 java -jar 执行的需求。其余部分的脚本仍然是必需的。 - Steve
1
非常有用,当/etc/init.d或systemd不可用时,感谢分享。 - bernardn
1
@Steve:不,你正在重新发明轮子。哦,我们现在有systemd了。 - Martin Schröder
当您需要向JVM传递参数(例如-javaagent或-D参数)时,这是唯一的方式,感谢@Steve! - Dyorgio

14

如果你想使用Spring Boot 1.2.5与Spring Boot Maven插件1.3.0.M2,请使用以下解决方案:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.2.5.RELEASE</version>
</parent>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <version>1.3.0.M2</version>
            <configuration>
                <executable>true</executable>
            </configuration>
        </plugin>
    </plugins>
</build>

<pluginRepositories>
    <pluginRepository>
        <id>spring-libs-milestones</id>
        <url>http://repo.spring.io/libs-milestone</url>
    </pluginRepository> 
</pluginRepositories>

然后像往常一样编译:mvn clean package,创建一个符号链接ln -s /.../myapp.jar /etc/init.d/myapp,将其设为可执行文件chmod +x /etc/init.d/myapp并启动它service myapp start(适用于Ubuntu服务器)。


可执行的WAR文件怎么样?使用WAR布局对我不起作用。 - Radu Toader
有趣的是,这适用于 1.3.0.M2 版本,但当我尝试使用 1.3.0.RC1 时出现了错误。 - JBCP
有没有想过用Gradle而不是Maven来完成这个任务? - Geir
在使用Gradle时,可以通过 springBoot { executable = true } 块来进行配置。 - Natix
@RaduToader:你能将WAR文件作为服务执行吗? - naveenkumarbv
最终我使用war/jar文件配置了systemd,因为这样更容易管理启动/重启和开机启用。 - Radu Toader

9

我知道这是一个较旧的问题,但我想提供另一种方式,那就是appassembler-maven-plugin。以下是我的POM中的相关部分,包括我们发现有用的许多其他选项值:

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>appassembler-maven-plugin</artifactId>
    <configuration>
        <generateRepository>true</generateRepository>
        <repositoryLayout>flat</repositoryLayout>
        <useWildcardClassPath>true</useWildcardClassPath>
        <includeConfigurationDirectoryInClasspath>true</includeConfigurationDirectoryInClasspath>
        <configurationDirectory>config</configurationDirectory>
        <target>${project.build.directory}</target>
        <daemons>
            <daemon>
                <id>${installer-target}</id>
                <mainClass>${mainClass}</mainClass>
                <commandLineArguments>
                    <commandLineArgument>--spring.profiles.active=dev</commandLineArgument>
                    <commandLineArgument>--logging.config=${rpmInstallLocation}/config/${installer-target}-logback.xml</commandLineArgument>
                </commandLineArguments>
                <platforms>
                    <platform>jsw</platform>
                </platforms>
                <generatorConfigurations>
                    <generatorConfiguration>
                        <generator>jsw</generator>
                        <includes>
                            <include>linux-x86-64</include>
                        </includes>
                        <configuration>
                            <property>
                                <name>wrapper.logfile</name>
                                <value>logs/${installer-target}-wrapper.log</value>
                            </property>
                            <property>
                                <name>wrapper.logfile.maxsize</name>
                                <value>5m</value>
                            </property>
                            <property>
                                <name>run.as.user.envvar</name>
                                <value>${serviceUser}</value>
                            </property>
                            <property>
                                <name>wrapper.on_exit.default</name>
                                <value>RESTART</value>
                            </property>
                        </configuration>
                    </generatorConfiguration>
                </generatorConfigurations>
                <jvmSettings>
                    <initialMemorySize>256M</initialMemorySize>
                    <maxMemorySize>1024M</maxMemorySize>
                    <extraArguments>
                        <extraArgument>-server</extraArgument>
                    </extraArguments>
                </jvmSettings>
            </daemon>
        </daemons>
    </configuration>
    <executions>
        <execution>
            <id>generate-jsw-scripts</id>
            <phase>package</phase>
            <goals>
                <goal>generate-daemons</goal>
            </goals>
        </execution>
    </executions>
</plugin>

8
作为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>

请确保exexmljar在同一个文件夹中。
之后以管理员权限打开命令提示符,并将其安装到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,输入管理工具,然后从中选择服务。然后右键单击选择运行/停止选项。


我已经按照相同的步骤在公司内部网络环境中运行Spring Boot Jar作为Windows服务,但该服务无法启动。出现了一个窗口并显示以下错误信息: 错误:1067 进程意外终止请问您能否提供帮助或建议需要做些什么? - Nikhil Singh Bhadoriya
你有足够的权限来做这件事吗?如果你是管理员,这不会造成任何问题。请确认你是否拥有管理员权限。 - Arundev
请尝试这个,也许可以帮助您解决问题:服务无法启动,错误1067,进程意外终止。 - Arundev
感谢您的快速回复,我通过纠正XML文件中的标签问题,使我的服务成功运行起来了。 - Nikhil Singh Bhadoriya

5
这里有一个脚本,可以将可执行的jar包部署为systemd服务。它会创建一个用于服务的用户和.service文件,并将jar文件放置在/var下,并进行一些基本的权限锁定。
#!/bin/bash

# Argument: The jar file to deploy
APPSRCPATH=$1

# Argument: application name, no spaces please, used as folder name under /var
APPNAME=$2

# Argument: the user to use when running the application, may exist, created if not exists
APPUSER=$3

# Help text
USAGE="
Usage: sudo $0 <jar-file> <app-name> <runtime-user>
If an app with the name <app-name> already exist, it is stopped and deleted.
If the <runtime-user> does not already exist, it is created.
"

# Check that we are root
if [ ! "root" = "$(whoami)" ]; then
    echo "Must be root. Please use e.g. sudo"
    echo "$USAGE"
    exit
fi

# Check arguments
if [ "$#" -ne 3 -o ${#APPSRCPATH} = 0 -o ${#APPNAME} = 0 -o ${#APPUSER} = 0 ]; then
    echo "Incorrect number of parameters."
    echo "$USAGE"
    exit
fi

if [ ! -f $APPSRCPATH ]; then
    echo "Can't find jar file $APPSRCPATH"
    echo "$USAGE"
    exit
fi

# Infered values
APPFILENAME=$(basename $APPSRCPATH)
APPFOLDER=/var/javaapps/$APPNAME
APPDESTPATH=$APPFOLDER/$APPFILENAME

# Stop the service if it already exist and is running
systemctl stop $APPNAME >/dev/null 2>&1

# Create the app folder, deleting any previous content
rm -fr $APPFOLDER
mkdir -p $APPFOLDER

# Create the user if it does not exist
if id "$APPUSER" >/dev/null 2>&1; then
    echo "Using existing user $APPUSER"
else
    adduser --disabled-password --gecos "" $APPUSER
    echo "Created user $APPUSER"
fi

# Place app in app folder, setting owner and rights
cp $APPSRCPATH $APPDESTPATH
chown $APPUSER $APPDESTPATH
chmod 500 $APPDESTPATH
echo "Added or updated the $APPDESTPATH file"

# Create the .service file used by systemd
echo "
[Unit]
Description=$APPNAME
After=syslog.target
[Service]
User=$APPUSER
ExecStart=/usr/bin/java -jar $APPDESTPATH
SuccessExitStatus=143
[Install]
WantedBy=multi-user.target
" > /etc/systemd/system/$APPNAME.service
echo "Created the /etc/systemd/system/$APPNAME.service file"

# Reload the daemon
systemctl daemon-reload

# Start the deployed app
systemctl start $APPNAME
systemctl status $APPNAME

例子: 在此输入图片描述


1
删除旧目录内容的问题在于你可能会误删配置文件或其他重要文件。不过脚本还是很不错的。 - TheRealChx101

5
我最终为WAR/JAR布局创建了systemd服务。我使用java -jar命令,因为它更加灵活。我还尝试将ExecStart=spring-mvc.war放入其中,但即使该文件是可执行的,我也遇到了“Exec format error”的错误。
无论如何,现在所有的发行版都支持systemd,并且提供了一个很好的解决方案来重定向日志(当服务甚至无法启动时,syserr非常重要,log4j文件位置将为空 :))。
cat /etc/systemd/system/spring-mvc.service 
[Unit]
Description=Spring MVC Java Service

[Service]
User=spring-mvc
# The configuration file application.properties should be here:
WorkingDirectory=/usr/local/spring-mvc


# Run ExecStartPre with root-permissions
PermissionsStartOnly=true

ExecStartPre=-/bin/mkdir -p /var/log/spring-mvc


ExecStartPre=/bin/chown -R spring-mvc:syslog /var/log/spring-mvc
ExecStartPre=/bin/chmod -R 775 /var/log/spring-mvc



#https://www.freedesktop.org/software/systemd/man/systemd.service.html#ExecStart=
ExecStart=/usr/bin/java \
        -Dlog4j.configurationFile=log4j2-spring.xml \
        -DLog4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector \
        -Dspring.profiles.active=dev \
        -Denvironment-type=dev \
        -XX:+UseConcMarkSweepGC \
        -XX:CMSInitiatingOccupancyFraction=80 \
        -XX:NewSize=756m \
        -XX:MetaspaceSize=256m \
        -Dsun.net.inetaddr.ttl=5 \
        -Xloggc:/var/log/spring-mvc/gc.log \
        -verbose:gc \
        -verbosegc \
        -XX:+DisableExplicitGC \
        -XX:+PrintGCDetails \
        -XX:+PrintGCDateStamps \
        -XX:+PreserveFramePointer \
        -XX:+StartAttachListener \
        -Xms1024m \
        -Xmx1024m \
        -XX:+HeapDumpOnOutOfMemoryError \
        -jar spring-mvc.war

SuccessExitStatus=143
StandardOutput=journal
StandardError=journal


KillSignal=SIGINT
TimeoutStopSec=20
Restart=always
RestartSec=5
StartLimitInterval=0
StartLimitBurst=10

LimitNOFILE=500000
LimitNPROC=500000

#https://www.freedesktop.org/software/systemd/man/systemd.exec.html#LimitCPU=
#LimitCPU=, LimitFSIZE=, LimitDATA=, LimitSTACK=, LimitCORE=, LimitRSS=, LimitNOFILE=, LimitAS=, LimitNPROC=, LimitMEMLOCK=, LimitLOCKS=, LimitSIGPENDING=, LimitMSGQUEUE=, LimitNICE=, LimitRTPRIO=, LimitRTTIME=¶

SyslogIdentifier=spring-mvc

[Install]
WantedBy=multi-user.target


# https://www.freedesktop.org/software/systemd/man/journalctl.html
#check logs --- journalctl -u spring-mvc -f -o cat

rsyslog - 将应用程序的syslog输入重定向到特定文件夹/文件

cat /etc/rsyslog.d/30-spring-mvc.conf 
if $programname == 'spring-mvc' then /var/log/spring-mvc/spring-mvc.log
& stop

logrotate

cat /etc/logrotate.d/spring-mvc.conf 
/var/log/spring-mvc/spring-mvc.log
{
    daily
    rotate 30
    maxage 30
    copytruncate
    missingok
    notifempty
    compress
    dateext
    dateformat _%Y-%m-%d_%H-%M
    delaycompress
    create 644 spring-mvc syslog
    su spring-mvc syslog
}

日志轮换垃圾回收

cat /etc/logrotate.d/spring-mvc-gc.conf 
/var/log/spring-mvc/gc.log
{
    daily
    rotate 30
    maxage 30
    copytruncate
    missingok
    notifempty
    compress
    dateext
    dateformat _%Y-%m-%d_%H-%M
    delaycompress
    create 644 spring-mvc syslog
    su spring-mvc syslog
}

Spring Boot 不会自动管理日志文件的轮换吗? - TheRealChx101
1
如果您有一个写入控制台的应用程序,最好对其进行一些处理。此外,如果应用程序无法启动,并且没有将任何内容写入日志记录,则可能是因为在日志记录框架设置之前就出现了异常,并且该错误存在于system.out/err中。 - Radu Toader

4
我正在尝试制作Spring Boot应用程序,并将其呈现为“init.d”样式的shell脚本,然后在末尾附加压缩的Java应用程序。
通过将这些脚本从/etc/init.d/spring-app符号链接到/opt/spring-app.jar,并将该jar设置为可执行权限,可以实现“/etc/init.d/spring-app start”、“/etc/init.d/spring-app stop”和其他可能性(如status)的操作。
可能是因为Spring Boot的init.d样式脚本看起来具有必要的神奇字符串(例如# Default-Start: 2 3 4 5),因此chkconfig可以将其添加为“服务”。
但我想让它与systemd一起使用。
为了使此工作正常,我尝试了上面其他答案中的许多食谱,但它们都不能在Centos 7.2上与Springboot 1.3一起跟踪进程ID(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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接