【问题标题】:Spring Boot application as a ServiceSpring Boot 应用程序即服务
【发布时间】:2014-02-25 13:16:51
【问题描述】:

如何在Linux系统中很好地配置打包为可执行jar即服务的Spring Boot应用程序?这是推荐的方法,还是应该将此应用程序转换为 war 并将其安装到 Tomcat 中?

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

如果我使用可执行文件 jar 的方法合适,我正在寻找一般建议/指导或示例 init.d 脚本。

【问题讨论】:

标签: linux spring-boot service startup init.d


【解决方案1】:

我不知道使用 Java 应用程序执行此操作的“标准”收缩包装方式,但这绝对是一个好主意(如果他们想从操作系统的保持活动和监视功能中受益在那里)。从 Spring Boot 工具支持(maven 和 gradle)中提供一些东西在路线图上,但现在你可能不得不自己动手。我现在知道的最好的解决方案是Foreman,它具有声明性方法和用于打包各种标准操作系统格式(monit、sys V、upstart 等)的初始化脚本的一行命令。还有证据表明人们使用 gradle 进行设置(例如 here)。

【讨论】:

    【解决方案2】:

    在这个问题中,@PbxMan 的回答应该可以帮助您入门:

    Run a Java Application as a Service on Linux

    编辑:

    还有另一种不太好的方法可以在重启时启动进程,使用 cron:

    @reboot user-to-run-under /usr/bin/java -jar /path/to/application.jar
    

    这可行,但没有为您的应用程序提供好的启动/停止界面。无论如何,您仍然可以简单地 kill 它...

    【讨论】:

    • 并非如此,因为 Spring Boot 提供了特殊功能来执行此操作。
    【解决方案3】:

    您也可以使用supervisord,这是一个非常方便的守护进程,可以用来轻松控制服务。这些服务是由简单的配置文件定义的,这些文件定义了在哪个目录中与哪个用户一起执行什么,等等,有无数的选项。 supervisord 的语法非常简单,因此它是编写 SysV 初始化脚本的一个很好的替代方案。

    这里有一个简单的 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,它会向您显示一个提示,您可以在其中启动、停止和状态您的应用程序。

    命令行

    # sudo supervisorctl
    yourapp             RUNNING   pid 123123, uptime 1 day, 15:00:00
    supervisor> stop yourapp
    supervisor> start yourapp
    

    如果supervisord 守护进程已经在运行,并且您已经为服务添加了配置而无需重新启动守护进程,您只需在supervisorctl shell 中执行rereadupdate 命令即可。

    这确实为您提供了使用 SysV Init 脚本所具有的所有灵活性,但易于使用和控制。看看documentation

    【讨论】:

    • 终于有了开箱即用的东西。非常感谢supervisord的提示。
    • 这与systemd 的作用相同,后者内置于大多数当前的 Linux 发行版中。
    【解决方案4】:

    以下是在 Linux 中将 Java 应用程序安装为系统服务的最简单方法。

    假设您使用的是systemd(现在任何现代发行版都这样做):

    首先,在/etc/systemd/system 中创建一个服务文件,命名为 e.g. 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

    【讨论】:

    • 很遗憾 systemd 不适用于 Centos 6
    • 它怎么知道如何阻止它?记录pid然后杀掉它?
    • 使用 Spring Boot 1.3+,您可以生成一个完全可执行的 war 文件,因此不需要 java -jar ... 位,只需在此处使用文件名即可。
    • 我更喜欢使用完整的 java 命令行,因为这样你可以添加 jvm 参数。
    • 对于正确的启动顺序,您可能需要将排序语句添加到 [Unit] 部分,例如After=mysql.service, Before=apache2.service.
    【解决方案5】:

    我刚开始自己​​做这件事,所以以下是我目前为止的 CentOS init.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
    

    停止时,它将尝试使用 Spring Boot Actuator 执行受控关闭。但是,如果 Actuator 未配置或未能在合理的时间范围内关闭(我给它 5 秒,确实有点短),该进程将被终止。

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

    【讨论】:

    • 无需编写自己的启动/停止脚本。这是从 Spring Boot 1.3 及更高版本开始提供的。有关详细信息,请参阅docs.spring.io/spring-boot/docs/current/reference/htmlsingle/…
    • 很高兴知道这是一个选项,但它所做的只是消除了使用java -jar 执行的需要。脚本的其余部分仍然需要。
    • 当 /etc/init.d 或 systemd 不是一个选项时非常有用,谢谢分享。
    • @Steve:不。你正在重新发明轮子。哦,我们现在有了 systemd。
    • 当您需要将参数传递给 JVM(如 -javaagent 或 -D 参数)时,这是唯一的方式,tks @Steve !
    【解决方案6】:

    我的 Centos 6 / RHEL 的 SysVInit 脚本(还不理想)。该脚本需要ApplicationPidListener

    /etc/init.d/app的来源

    #!/bin/sh
    #
    # app Spring Boot Application 
    #
    # chkconfig:   345 20 80
    # description: App Service
    #           
    
    ### BEGIN INIT INFO
    # Provides: App
    # Required-Start: $local_fs $network
    # Required-Stop: $local_fs $network
    # Default-Start: 3 4 5 
    # Default-Stop: 0 1 2 6
    # Short-Description: Application
    # Description:      
    ### END INIT INFO
    
    # Source function library.
    . /etc/rc.d/init.d/functions
    
    # Source networking configuration.
    . /etc/sysconfig/network
    
    exec="/usr/bin/java"
    prog="app"
    app_home=/home/$prog/
    user=$prog
    
    [ -e /etc/sysconfig/$prog ] && . /etc/sysconfig/$prog
    
    lockfile=/var/lock/subsys/$prog    
    pid=$app_home/$prog.pid
    
    start() {
    
        [ -x $exec ] || exit 5
        [ -f $config ] || exit 6
        # Check that networking is up.
        [ "$NETWORKING" = "no" ] && exit 1
        echo -n $"Starting $prog: "
        cd $app_home
        daemon --check $prog --pidfile $pid --user $user $exec $app_args &
        retval=$?
        echo
        [ $retval -eq 0 ] && touch $lockfile
        return $retval
    }
    
    stop() {
        echo -n $"Stopping $prog: "
        killproc -p $pid $prog
        retval=$?
        [ $retval -eq 0 ] && rm -f $lockfile
        return $retval
    }
    
    restart() {
        stop
        start
    }
    
    reload() {
        restart
    }
    
    force_reload() {
        restart
    }
    
    rh_status() {
        status -p $pid $prog
    }
    
    rh_status_q() {
        rh_status >/dev/null 2>&1
    }
    
    case "$1" in
        start)
            rh_status_q && exit 0
            $1
            ;;
        stop)
            rh_status_q || exit 0
            $1
            ;;
        restart)
            $1
            ;;
        reload)
            rh_status_q || exit 7
            $1
            ;;
        force-reload)
            force_reload
            ;;
        status)
            rh_status
            ;;
        condrestart|try-restart)
            rh_status_q || exit 0
            restart
            ;;
        *)
            echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload}"
            exit 2
    esac
    exit $?
    

    示例配置文件/etc/sysconfig/app:

    exec=/opt/jdk1.8.0_05/jre/bin/java
    
    user=myuser
    app_home=/home/mysuer/
    
    app_args="-jar app.jar"
    
    pid=$app_home/app.pid
    

    【讨论】:

      【解决方案7】:

      你在使用 Maven 吗?那你应该试试 AppAssembler 插件:

      Application Assembler Plugin 是一个 Maven 插件,用于生成用于启动 java 应用程序的脚本。 ...所有工件(依赖项 + 项目中的工件)都添加到生成的 bin 脚本中的类路径中。

      支持的平台:

      Unix 变体

      Windows NT(不支持 Windows 9x)

      Java 服务包装器 (JSW)

      见:http://mojo.codehaus.org/appassembler/appassembler-maven-plugin/index.html

      【讨论】:

        【解决方案8】:

        我知道这是一个较老的问题,但我想提出另一种方式,即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>
        

        【讨论】:

          【解决方案9】:

          以下适用于springboot 1.3及以上:

          作为 init.d 服务

          可执行 jar 具有通常的启动、停止、重新启动和状态命令。它还将在通常的 /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
          

          然后根据需要在您希望应用程序在启动时启动/停止的任何运行级别设置一个链接。


          作为系统服务

          要运行安装在 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),否则它将失败并出现错误“Permission denied”。

          参考

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

          【讨论】:

          • “完全可执行的 JAR”方法是如何工作的?我使用 CentOS 6.6。我在我的pom.xml 中添加了&lt;executable&gt;true&lt;/executable&gt;,但是打包的JAR 文件没有执行(..../myapp.jar ... cannot execute binary file。)
          • 此答案适用于尚未发布的当前 1.3 里程碑。 1.1 和 1.2 分支需要在这里检查其他响应。
          • 您知道如何将 spring 的参数(例如 -Dspring.profiles.active=prod)传递给此服务吗?问题 - stackoverflow.com/questions/31242291/…
          • 我无法停止 spring-boot 应用程序。 /etc/init.d stop 没有停止应用程序,它正在尝试重新启动它。
          • 如果你想监视进程并在它死掉而不写系统守护进程的情况下重新启动它,请查看patrickgrimard.com/2014/06/06/…
          【解决方案10】:

          如果您想将 Spring Boot 1.2.5 与 Spring Boot Maven Plugin 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 布局。
          • 有趣的是,这适用于发行版1.3.0.M2,但是当我尝试1.3.0.RC1 时出现错误。
          • 知道如何用 gradle 而不是 maven 做到这一点吗?
          • 使用 Gradle 时,此配置使用 springBoot { executable = true } 块完成。
          • @RaduToader :您是否能够将 WAR 文件作为服务执行?
          【解决方案11】:

          这是一个将可执行 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
          

          示例:

          【讨论】:

          • 删除旧目录内容的问题最终可能会删除配置文件或其他重要文件。不过还是不错的剧本
          【解决方案12】:

          我正在尝试制作以“init.d”样式的 shell 脚本形式呈现的 springboot 应用程序,并在末尾添加一个压缩的 java 应用程序

          通过将这些脚本从 /etc/init.d/spring-app 符​​号链接到 /opt/spring-app.jar 并将 jar 更改为可执行,可以使“/etc/init.d/spring -app start" "/etc/init.d/spring-app stop" 和状态工作等其他可能性

          据推测,来自 springboot 的 init.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
          

          【讨论】:

            【解决方案13】:

            可以在 Ubuntu 中使用 Systemd 服务来完成

            [Unit]
            Description=A Spring Boot application
            After=syslog.target
            
            [Service]
            User=baeldung
            ExecStart=/path/to/your-app.jar SuccessExitStatus=143
            
            [Install] 
            WantedBy=multi-user.target
            

            您可以点击此链接获得更详细的描述和不同的方法。 http://www.baeldung.com/spring-boot-app-as-a-service

            【讨论】:

              【解决方案14】:

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

              确保 exexml 以及 jar 在同一个文件夹中。

              在此打开 Administrator previlege 中的命令提示符 并将其安装到 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,然后从中选择 service。然后右击选择选项-运行/停止

              【讨论】:

              • 我已经按照相同的步骤在公司的 Intranet env 中将 spring boot jar 作为 windows 服务运行,但是该服务没有启动。有一个窗口出现错误:错误:1067 进程意外终止您能帮忙或建议需要做什么吗?
              • 您是否拥有这样做的所有权限?如果您是管理员,这不会导致任何问题。请检查您是否有管理员权限。
              • stackoverflow.com/questions/18205111/… 你可以试试这个可能会帮助你解决问题。
              • 感谢您的快速响应,通过更正 xml 文件中的标签问题,我启动并运行了我的服务。
              【解决方案15】:

              跟进 Chad 的出色回答,如果您收到 “错误:无法找到或加载主类” 的错误 - 并且您花了几个小时尝试解决它,无论您是否执行启动您的 java 应用程序或从 systemd 本身启动它的 shell 脚本 - 您知道您的类路径是 100% 正确的,例如手动运行 shell 脚本与运行 systemd execstart 中的脚本一样有效。 确保您是以正确的用户身份运行的!在我的情况下,我尝试了不同的用户,经过相当长的故障排除 - 我终于有预感,将 root 作为用户 - 瞧,应用程序正确启动。在确定这是一个错误的用户问题后,我chown -R user:user 文件夹和子文件夹以及应用程序作为指定的用户和组正确运行,因此不再需要以 root 身份运行它(安全性差)。

              【讨论】:

                【解决方案16】:

                在 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 应用程序完成此过程,它就会查找匹配的环境变量,并相应地使用找到的任何环境变量。

                此 SO Q&A 中更详细地强调了这一点,标题为:How to set a Spring Boot property with an underscore in its name via Environment Variables?

                参考文献

                【讨论】:

                • 我个人不喜欢分散配置文件或相关文件。理想情况下,我喜欢将所有东西都放在一个地方,这样您在维护期间或其他人必须接管您的东西时只需要在一个地方查看。
                【解决方案17】:

                我最终为 WAR/JAR 布局提供了 systemd 服务

                我调用 java -jar 是因为它更灵活。也试过把 ExecStart=spring-mvc.war 但即使是可执行的,我得到'Exec format error'

                无论如何,这些天来,systemd 存在于所有发行版中,并提供了一个很好的解决方案来重定向日志(当您的服务甚至不启动 log4j 文件位置时,syserr 很重要文件位置将为空:)。

                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 - 将系统日志输入从应用重定向到特定文件夹/文件

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

                登录

                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
                }
                

                logrotate gc

                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 不管理自己的日志文件轮换吗?
                • 如果您有写入控制台的应用程序,您最好用它做点什么。此外,如果应用程序没有启动,并且没有向日志写入任何内容,可能是因为它在日志框架设置之前有一个异常,并且该错误存在于 system.out/err
                【解决方案18】:

                Spring Boot项目的build.gradle文件需要如下配置。

                build.gradle

                jar {
                    baseName = 'your-app'
                    version = version
                }
                
                springBoot {
                    buildInfo()
                    executable = true   
                    mainClass = "com.shunya.App"
                }
                

                可执行文件=真

                这是在 unix 系统(Centos 和 Ubuntu)上制作完全可执行的 jar 所必需的

                创建 .conf 文件

                如果要配置自定义 JVM 属性或 Spring Boot 应用程序运行参数,则可以创建一个与 Spring Boot 应用程序名称同名的 .conf 文件,并将其与 jar 文件并行放置。

                考虑到 your-app.jar 是你的 Spring Boot 应用的名字,那么你可以创建如下文件。

                JAVA_OPTS="-Xms64m -Xmx64m"
                RUN_ARGS=--spring.profiles.active=prod
                LOG_FOLDER=/custom/log/folder
                

                此配置将为 Spring Boot 应用程序设置 64 MB 内存并激活 prod 配置文件。

                在 linux 中创建新用户

                为了增强安全性,我们必须创建一个特定用户来将 Spring Boot 应用程序作为服务运行。

                创建一个新用户

                sudo useradd -s /sbin/nologin springboot
                

                在 Ubuntu / Debian 上,将上述命令修改如下:

                sudo useradd -s /usr/sbin/nologin springboot
                

                设置密码

                sudo passwd springboot
                

                使springboot成为可执行文件的所有者

                chown springboot:springboot your-app.jar
                

                防止修改jar文件

                chmod 500 your-app.jar
                

                这将配置jar的权限,使其不能被写入,只能由其所有者springboot读取或执行。

                您可以选择使用更改属性 (chattr) 命令将您的 jar 文件设为不可变。

                sudo chattr +i your-app.jar
                

                也应为相应的 .conf 文件设置适当的权限。 .conf 只需要读取权限(八进制 400)而不是读取 + 执行(八进制 500)权限

                chmod 400 your-app.conf
                

                创建 Systemd 服务

                /etc/systemd/system/your-app.service

                [Unit]
                Description=Your app description
                After=syslog.target
                
                [Service]
                User=springboot
                ExecStart=/var/myapp/your-app.jar
                SuccessExitStatus=143
                
                [Install]
                WantedBy=multi-user.target
                

                进程被操作系统杀死时自动重启

                添加以下两个属性(Restart 和 RestartSec)以在失败时自动重启进程。

                /etc/systemd/system/your-app.service

                [Service]
                User=springboot
                ExecStart=/var/myapp/your-app.jar
                SuccessExitStatus=143
                Restart=always
                RestartSec=30
                

                此更改将使 Spring Boot 应用程序在失败时重启,延迟 30 秒。如果您使用 systemctl 命令停止服务,则不会发生重新启动。

                在系统启动时安排服务

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

                在系统启动时启用 Spring Boot 应用程序

                sudo systemctl enable your-app.service
                

                启动和停止服务

                systemctl 可以在 Ubuntu 16.04 LTS 和 18.04 LTS 中用于启动和停止进程。

                开始进程

                sudo systemctl start your-app
                

                停止进程

                sudo systemctl stop your-app
                

                参考文献

                https://docs.spring.io/spring-boot/docs/current/reference/html/deployment-install.html

                【讨论】:

                • 很好...现在的问题是使用该非 sudoer 用户在特权端口上运行应用程序。
                【解决方案19】:

                创建一个名为 your-app.service (rest-app.service) 的脚本。 我们应该将此脚本放在 /etc/systemd/system 目录中。 这是脚本的示例内容

                [Unit]
                Description=Spring Boot REST Application
                After=syslog.target
                
                [Service]
                User=javadevjournal
                ExecStart=/var/rest-app/restdemo.jar
                SuccessExitStatus=200
                
                [Install]
                WantedBy=multi-user.target
                

                下一步:

                 service rest-app start
                

                参考文献

                enter link description here

                【讨论】:

                【解决方案20】:

                对于 SpringBoot 2.4.4,除了说明 @ismael

                我在我的 maven pom.xml 中有以下内容以使其成为可执行的 jar

                <build>
                    <plugins>
                        <plugin>
                            <groupId>org.springframework.boot</groupId>
                            <artifactId>spring-boot-maven-plugin</artifactId>               
                            <configuration>
                                <executable>true</executable>
                            </configuration>
                            <executions>
                                <execution>
                                    <goals>
                                        <goal>repackage</goal>
                                    </goals>
                                </execution>
                            </executions>
                        </plugin>
                    </plugins>
                </build>
                

                【讨论】:

                  猜你喜欢
                  • 2016-12-04
                  • 1970-01-01
                  • 2015-11-30
                  • 1970-01-01
                  • 2016-12-18
                  • 2019-04-28
                  • 2020-09-22
                  • 2014-06-09
                  • 2019-08-06
                  相关资源
                  最近更新 更多