在 Linux 上运行 Java 应用程序作为服务

我编写了一个运行在标准虚拟托管 Linux 解决方案上的 Java 服务器应用程序。应用程序一直在运行,监听套接字连接并为其创建新的处理程序。它是客户机-服务器应用程序的服务器端实现。

我启动它的方法是将它包含在服务器的启动 Rc.local脚本中。但是一旦启动,我不知道如何访问它停止它,如果我想安装更新,所以我必须重新启动服务器,以便重新启动应用程序。

在 Windows PC 上,对于这种类型的应用程序,我可以创建一个 Windows 服务,然后我可以停止和启动它,因为我想要的。在 Linux 机器上是否有类似的东西,这样如果我启动这个应用程序,我就可以停止它并重新启动它,而无需完全重新启动服务器。

我的应用程序名为 WebServer.exe,它是在服务器启动时通过将其包含在我的 Rc.local中来启动的,比如:

java -jar /var/www/vhosts/myweb.com/phpserv/WebServer.jar &

我是一个有点菜鸟在 Linux,所以任何例子都会感激与任何职位。不过,我有 SSH,和完整的 FTP 访问框安装任何更新,以及访问 Plesk 面板。

225966 次浏览

另一个非常流行的替代品是 Java 服务包装器,它在 OSS 社区中也非常流行。

然而一旦开始我不知道如何进入它来阻止它

您可以编写一个简单的 stop 脚本,该脚本可以对 Java 进程进行 greps,提取 PID 并对其调用 kill。不是很高级,但很直接。 这样的话可能会有所帮助:

#!/bin/bash
PID = ps ax | grep "name of your app" | cut -d ' ' -f 1
kill $PID

Linux 服务 init 脚本存储在 /etc/init.d中。您可以复制和定制 /etc/init.d/skeleton文件,然后调用

service [yourservice] start|stop|restart

参见 http://www.ralfebert.de/blog/java/debian_daemon/。它适用于 Debian (也适用于 Ubuntu) ,但适用于更多的发行版。

一个简单的解决方案是创建一个脚本 start.sh,该脚本通过 nohup 运行 Java,然后将 PID 存储到一个文件中:

nohup java -jar myapplication.jar > log.txt 2> errors.txt < /dev/null &
PID=$!
echo $PID > pid.txt

然后,您的 stop 脚本 stop.sh 将从文件中读取 PID 并终止应用程序:

PID=$(cat pid.txt)
kill $PID

当然,我遗漏了一些细节,比如检查进程是否存在,如果完成了,删除 pid.txt

可以使用 廉价服务器JMX与 Java 服务通信。

我在这里写了另一个简单的包装:

#!/bin/sh
SERVICE_NAME=MyService
PATH_TO_JAR=/usr/local/MyProject/MyJar.jar
PID_PATH_NAME=/tmp/MyService-pid
case $1 in
start)
echo "Starting $SERVICE_NAME ..."
if [ ! -f $PID_PATH_NAME ]; then
nohup java -jar $PATH_TO_JAR /tmp 2>> /dev/null >> /dev/null &
echo $! > $PID_PATH_NAME
echo "$SERVICE_NAME started ..."
else
echo "$SERVICE_NAME is already running ..."
fi
;;
stop)
if [ -f $PID_PATH_NAME ]; then
PID=$(cat $PID_PATH_NAME);
echo "$SERVICE_NAME stoping ..."
kill $PID;
echo "$SERVICE_NAME stopped ..."
rm $PID_PATH_NAME
else
echo "$SERVICE_NAME is not running ..."
fi
;;
restart)
if [ -f $PID_PATH_NAME ]; then
PID=$(cat $PID_PATH_NAME);
echo "$SERVICE_NAME stopping ...";
kill $PID;
echo "$SERVICE_NAME stopped ...";
rm $PID_PATH_NAME
echo "$SERVICE_NAME starting ..."
nohup java -jar $PATH_TO_JAR /tmp 2>> /dev/null >> /dev/null &
echo $! > $PID_PATH_NAME
echo "$SERVICE_NAME started ..."
else
echo "$SERVICE_NAME is not running ..."
fi
;;
esac

您可以按照完整的教程学习 init.d 给你和 systemd (ubuntu 16 +) 给你

如果需要输出日志,请替换 2

nohup java -jar $PATH_TO_JAR /tmp 2>> /dev/null >> /dev/null &

排队等候

nohup java -jar $PATH_TO_JAR >> myService.out 2>&1&

SpringBoot 应用程序即服务中,我可以推荐基于 Python 的 supervisord应用程序。有关更多信息,请参见堆栈溢出问题。设置起来非常简单。

也许不是最好的 dev-ops 解决方案,但是对于局域网方或类似方面的服务器的一般使用是有好处的。

使用 screen运行您的服务器,然后在注销之前分离,这将保持进程运行,然后您可以在任何时候重新附加。

工作流程:

开始扫描: screen

启动服务器: java -jar minecraft-server.jar

按下分离键: Ctl-ad

重新连接: screen -r

更多信息请点击: https://www.gnu.org/software/screen/manual/screen.html

谈到 SpringBoot 应用程序即服务,我会选择 systemd版本,因为它是最简单、最不冗长、最适合集成到现代发行版(甚至是不那么现代的发行版,比如 CentOS 7.x)的版本。

其他答案可以根据您的平台提供定制脚本和设置。除此之外,这里还有一些我所知道的成熟的特殊用途项目:

  • 来自 TanukiSoftware 的 JSW
  • YAJSW 是上面提到的一个开放源码克隆。它是用 Java 编写的,它是一个保姆进程,根据配置管理子进程(代码)。可以在 windows/linux 上工作。
  • JSVC 是一个本地应用程序。它也是一个保姆过程,但是它通过 JNI 调用您的子应用程序,而不是作为一个子过程。

下面是一个示例 shell 脚本(确保用应用程序的名称替换 MATH 名称) :

#!/bin/bash


### BEGIN INIT INFO
# Provides:                 MATH
# Required-Start:           $java
# Required-Stop:            $java
# Short-Description:        Start and stop MATH service.
# Description:              -
# Date-Creation:            -
# Date-Last-Modification:   -
# Author:                   -
### END INIT INFO


# Variables
PGREP=/usr/bin/pgrep
JAVA=/usr/bin/java
ZERO=0


# Start the MATH
start() {
echo "Starting MATH..."
#Verify if the service is running
$PGREP -f MATH > /dev/null
VERIFIER=$?
if [ $ZERO = $VERIFIER ]
then
echo "The service is already running"
else
#Run the jar file MATH service
$JAVA -jar /opt/MATH/MATH.jar > /dev/null 2>&1 &
#sleep time before the service verification
sleep 10
#Verify if the service is running
$PGREP -f MATH  > /dev/null
VERIFIER=$?
if [ $ZERO = $VERIFIER ]
then
echo "Service was successfully started"
else
echo "Failed to start service"
fi
fi
echo
}


# Stop the MATH
stop() {
echo "Stopping MATH..."
#Verify if the service is running
$PGREP -f MATH > /dev/null
VERIFIER=$?
if [ $ZERO = $VERIFIER ]
then
#Kill the pid of java with the service name
kill -9 $($PGREP -f MATH)
#Sleep time before the service verification
sleep 10
#Verify if the service is running
$PGREP -f MATH  > /dev/null
VERIFIER=$?
if [ $ZERO = $VERIFIER ]
then
echo "Failed to stop service"
else
echo "Service was successfully stopped"
fi
else
echo "The service is already stopped"
fi
echo
}


# Verify the status of MATH
status() {
echo "Checking status of MATH..."
#Verify if the service is running
$PGREP -f MATH > /dev/null
VERIFIER=$?
if [ $ZERO = $VERIFIER ]
then
echo "Service is running"
else
echo "Service is stopped"
fi
echo
}


# Main logic
case "$1" in
start)
start
;;
stop)
stop
;;
status)
status
;;
restart|reload)
stop
start
;;
*)
echo $"Usage: $0 {start|stop|status|restart|reload}"
exit 1
esac
exit 0

要将 Java 代码作为守护进程(服务)运行,您可以编写基于 JNI 的存根。

Http://jnicookbook.owsiak.org/recipe-no-022/

获取基于 JNI 的示例代码。在这种情况下,您将以 Java 启动的代码守护化,并且在 C 中执行 main 循环。但是也可以将 main、 daemon、 service 循环放在 Java 中。

Https://github.com/mkowsiak/jnicookbook/tree/master/recipes/recipeno029

祝你和 JNI 玩得开心!

来自 弹簧启动参考指南

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

只需将 jar 符号链接到 init.d,以支持标准的 startstoprestartstatus命令。 假设您在/var/myapp 中安装了 Spring Boot 应用程序,要将 Spring Boot 应用程序作为 init.d 服务安装,只需创建一个符号链接:

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

一旦安装完毕,你可以按照通常的方式启动和停止服务,例如,在一个基于 Debian 的系统上:

$ service myapp start

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

继续阅读 以了解如何保护已部署的服务。

在按照写入的方式执行之后,我发现我的服务在日志中以这个错误消息 Start-stop-daemon: 未识别选项—— no-close启动失败。我已经设法通过创建一个配置文件 /var/myapp/myapp.conf来修复它,其内容如下

USE_START_STOP_DAEMON=false

可以将 war 作为 Linux 服务运行,您可能希望在打包之前强制输入 pom.xml 文件,因为有些发行版在 auto 模式下可能无法识别。为此,在 spring-boot-maven-plugin 插件中添加以下属性。

                    <embeddedLaunchScriptProperties>
<mode>service</mode>
</embeddedLaunchScriptProperties>

接下来,将 init.d 设置为:

ln -s myapp.war /etc/init.d/myapp

你就能逃跑了

service myapp start|stop|restart

Spring Boot 文档中还有许多其他选项,包括 Windows 服务。

我有 Netty java 应用程序,我想运行它作为一个服务与 Systemd。不幸的是,无论我使用什么类型,应用程序都会停止。最后我在屏幕上包装了 java 开始。下面是配置文件:

服务

[Unit]
Description=Netty service
After=network.target
[Service]
User=user
Type=forking
WorkingDirectory=/home/user/app
ExecStart=/home/user/app/start.sh
TimeoutStopSec=10
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target

开始

#!/bin/sh
/usr/bin/screen -L -dmS netty_app java -cp app.jar classPath

从这一点你可以使用 systemctl [start|stop|status] service