134

我编写了一个在标准虚拟托管 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 面板的访问权限。

4

16 回答 16

243

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

#!/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&
于 2014-01-22T12:53:49.893 回答
50

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

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

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

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

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

于 2012-06-26T08:41:43.670 回答
34

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

service [yourservice] start|stop|restart

请参阅http://www.ralfebert.de/blog/java/debian_daemon/。它适用于 Debian(因此,Ubuntu 也是如此),但适合更多发行版。

于 2012-06-26T08:41:25.907 回答
14

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

用于screen运行您的服务器,然后在注销之前分离,这将保持进程运行,然后您可以随时重新连接。

工作流程:

启动屏幕:screen

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

按下分离: Ctl-a,d

重新连接:screen -r

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

于 2015-06-13T21:21:16.970 回答
7

另一种也很流行的替代方法是Java Service Wrapper。这在 OSS 社区中也很流行。

于 2012-06-26T08:40:23.880 回答
5

Spring Boot 应用程序也称为服务,我会选择该systemd版本,因为它是最简单、最不冗长并且最好地集成到现代发行版(甚至是不太现代的发行版,如 CentOS 7.x)中。

于 2016-08-17T20:07:46.913 回答
4

最简单的方法是使用supervisord. 请在此处查看完整的详细信息:http: //supervisord.org/

更多信息:

https://askubuntu.com/questions/779830/running-an-executable-jar-file-when-the-system-starts/852485#852485

https://www.digitalocean.com/community/tutorials/how-to-install-and-manage-supervisor-on-ubuntu-and-debian-vps

于 2016-11-22T23:38:39.527 回答
4

这是一个示例 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
于 2017-03-20T14:43:13.260 回答
3

Spring Boot application as a Service,我可以推荐基于 Python 的supervisord应用程序。有关更多信息,请参阅该堆栈溢出问题。设置起来非常简单。

于 2015-01-06T10:23:51.360 回答
2

其他答案可以很好地根据您的平台提供自定义脚本和设置。除此之外,还有我所知道的成熟的、特殊用途的程序:

  • TanukiSoftware 的 JSW
  • YAJSW是上述的开源克隆。它是用Java编写的,是一个根据配置管理子进程(你的代码)的nanny进程。适用于windows/linux。
  • JSVC是一个原生应用程序。它也是一个保姆进程,但它通过 JNI 调用您的子应用程序,而不是作为子进程。
于 2017-03-16T03:40:43.740 回答
1

您可以使用Thrift 服务器JMX与您的 Java 服务进行通信。

于 2012-06-26T09:35:55.400 回答
1

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

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

获取基于 JNI 的示例代码。在这种情况下,您将对作为 Java 启动的代码进行守护,并在 C 中执行主循环。但也可以将主、守护、服务循环放在 Java 中。

https://github.com/mkowsiak/jnicookbook/tree/master/recipes/recipeNo029

JNI 玩得开心!

于 2017-06-05T07:34:05.600 回答
1

来自Spring Boot 参考指南

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

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

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

安装后,您可以按常规方式启动和停止服务。例如,在基于 Debian 的系统上:

$ service myapp start

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

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

按照所写的操作后,我发现我的服务无法启动,并在日志中显示此错误消息:start-stop-daemon: unrecognized option --no-close。我已经设法通过创建一个/var/myapp/myapp.conf包含以下内容的配置文件来修复它

USE_START_STOP_DAEMON=false
于 2018-01-29T15:54:00.350 回答
1

可以将战争作为 Linux 服务运行,并且您可能希望在打包之前强制输入 pom.xml 文件,因为某些发行版可能无法在自动模式下识别。为此,请在 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 服务。

于 2019-03-14T00:46:26.823 回答
1

我有 Netty java 应用程序,我想用 systemd 将它作为服务运行。不幸的是,无论我使用什么类型,应用程序都会停止。最后,我将 java start 包装在屏幕中。以下是配置文件:

服务

[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.

于 2019-11-19T07:55:10.033 回答
0

但是一旦开始,我不知道如何访问它来阻止它

您可以编写一个简单的停止脚本,对您的 java 进程进行 greps,提取 PID 并对其调用 kill。这不是花哨的,但它是直截了当的。像这样的东西可能会有所帮助:

#!/bin/bash
PID = ps ax | grep "name of your app" | cut -d ' ' -f 1
kill $PID
于 2012-06-26T08:41:07.430 回答