19

スプリング ブート「uber JAR」を procrun でラップしようとしています。

次の作業を実行すると、期待どおりに動作します。

java -jar my.jar

Windowsの起動時に自動的に起動するには、Spring Boot jarが必要です。これに対する最も良い解決策は、jar をサービスとして実行することです (スタンドアロンの tomcat と同じ)。

これを実行しようとすると、「Commons Daemon procrun failed with exit value: 3」というメッセージが表示されます

spring-boot ソースを見ると、カスタム クラスローダーを使用しているように見えます。

https://github.com/spring-projects/spring-boot/blob/master/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/JarLauncher.java

メイン メソッドを直接実行しようとすると、「ClassNotFoundException」も発生します。

java -cp my.jar my.MainClass

Spring Boot jar で (JarLauncher 経由ではなく) メイン メソッドを実行するために使用できる方法はありますか?

spring-boot と procrun の統合に成功した人はいますか?

http://wrapper.tanukisoftware.com/を認識しています。しかし、彼らのライセンスのために、私はそれを使用することができません。

アップデート

これで、procrun を使用してサービスを開始できました。

set SERVICE_NAME=MyService
set BASE_DIR=C:\MyService\Path
set PR_INSTALL=%BASE_DIR%prunsrv.exe

REM Service log configuration
set PR_LOGPREFIX=%SERVICE_NAME%
set PR_LOGPATH=%BASE_DIR%
set PR_STDOUTPUT=%BASE_DIR%stdout.txt
set PR_STDERROR=%BASE_DIR%stderr.txt
set PR_LOGLEVEL=Error

REM Path to java installation
set PR_JVM=auto
set PR_CLASSPATH=%BASE_DIR%%SERVICE_NAME%.jar

REM Startup configuration
set PR_STARTUP=auto
set PR_STARTIMAGE=c:\Program Files\Java\jre7\bin\java.exe 
set PR_STARTMODE=exe
set PR_STARTPARAMS=-jar#%PR_CLASSPATH%

REM Shutdown configuration
set PR_STOPMODE=java
set PR_STOPCLASS=TODO
set PR_STOPMETHOD=stop

REM JVM configuration
set PR_JVMMS=64
set PR_JVMMX=256

REM Install service
%PR_INSTALL% //IS//%SERVICE_NAME%

私は今、サービスを停止する方法を練習する必要があります。スプリングブート アクチュエータ シャットダウン JMX Bean を使用することを考えています。

現時点でサービスを停止するとどうなりますか。Windows はサービスを停止できません (ただし、停止済みとしてマークされます)、サービスはまだ実行されています (localhost を参照できます)、タスク マネージャーにプロセスについての言及はありません (目が見えない場合を除き、あまり良くありません)。

4

5 に答える 5

7

私も同様の問題に遭遇しましたが、他の誰か (Francesco Zanutto) が親切にも彼らの取り組みについてブログ記事を書いてくれたことを知りました。 彼らの解決策は私にとってはうまくいきました。彼らがこのコードを実現するために費やした時間を私は信用しません。

http://zazos79.blogspot.com/2015/02/spring-boot-12-run-as-windows-service.html

あなたの例で見たexeモードと比較して、彼はjvmの開始および停止モードを使用しています。これにより、彼は Spring Boot の JarLauncher を拡張して、Windows サービスからの「開始」コマンドと「停止」コマンドの両方を処理できるようになりました。

彼の例のように、実装に応じて複数のメイン メソッドを追加することになり、ランチャーによって呼び出されるメソッドを示す必要があります。私は Gradle を使用しており、build.gradle に以下を追加するだけで済みました。

springBoot{
    mainClass = 'mydomain.app.MyApplication'
}

私の Procrun インストール スクリプト:

D:\app\prunsrv.exe //IS//MyServiceName ^
--DisplayName="MyServiceDisplayName" ^
--Description="A Java app" ^
--Startup=auto ^
--Install=%CD%\prunsrv.exe ^
--Jvm=%JAVA_HOME%\jre\bin\server\jvm.dll ^
--Classpath=%CD%\SpringBootApp-1.1.0-SNAPSHOT.jar; ^
--StartMode=jvm ^
--StartClass=mydomain.app.Bootstrap ^
--StartMethod=start ^
--StartParams=start ^
--StopMode=jvm ^
--StopClass=mydomain.app.Bootstrap ^
--StopMethod=stop ^
--StopParams=stop ^
--StdOutput=auto ^
--StdError=auto ^
--LogPath=%CD% ^
--LogLevel=Debug

JarLauncher 拡張クラス:

package mydomain.app;


import org.springframework.boot.loader.JarLauncher;
import org.springframework.boot.loader.jar.JarFile;

public class Bootstrap extends JarLauncher {

    private static ClassLoader classLoader = null;
    private static Bootstrap bootstrap = null;

    protected void launch(String[] args, String mainClass, ClassLoader classLoader, boolean wait)
            throws Exception {
        Runnable runner = createMainMethodRunner(mainClass, args, classLoader);
        Thread runnerThread = new Thread(runner);
        runnerThread.setContextClassLoader(classLoader);
        runnerThread.setName(Thread.currentThread().getName());
        runnerThread.start();
        if (wait == true) {
            runnerThread.join();
        }
    }

    public static void start (String []args) {
        bootstrap = new Bootstrap ();
        try {
            JarFile.registerUrlProtocolHandler();
            classLoader = bootstrap.createClassLoader(bootstrap.getClassPathArchives());
            bootstrap.launch(args, bootstrap.getMainClass(), classLoader, true);
        }
        catch (Exception ex) {
            ex.printStackTrace();
            System.exit(1);
        }
    }

    public static void stop (String []args) {
        try {
            if (bootstrap != null) {
                bootstrap.launch(args, bootstrap.getMainClass(), classLoader, true);
                bootstrap = null;
                classLoader = null;
            }
        }
        catch (Exception ex) {
            ex.printStackTrace();
            System.exit(1);
        }
    }

    public static void main(String[] args) {
        String mode = args != null && args.length > 0 ? args[0] : null;
        if ("start".equals(mode)) {
            Bootstrap.start(args);
        }
        else if ("stop".equals(mode)) {
            Bootstrap.stop(args);
        }
    }

}

私の主なSpringアプリケーションクラス:

package mydomain.app;

import java.lang.management.ManagementFactory;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.ExitCodeGenerator;
import org.springframework.boot.SpringApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@ComponentScan
@EnableAutoConfiguration
public class MyApplication {

    private static final Logger logger = LoggerFactory.getLogger(MyApplication.class);
    private static ApplicationContext applicationContext = null;

    public static void main(String[] args) {
        String mode = args != null && args.length > 0 ? args[0] : null;

        if (logger.isDebugEnabled()) {
            logger.debug("PID:" + ManagementFactory.getRuntimeMXBean().getName() + " Application mode:" + mode + " context:" + applicationContext);
        }
        if (applicationContext != null && mode != null && "stop".equals(mode)) {
            System.exit(SpringApplication.exit(applicationContext, new ExitCodeGenerator() {
                @Override
                public int getExitCode() {
                    return 0;
                }
            }));
        }
        else {
            SpringApplication app = new SpringApplication(MyApplication.class);
            applicationContext = app.run(args);
            if (logger.isDebugEnabled()) {
                logger.debug("PID:" + ManagementFactory.getRuntimeMXBean().getName() + " Application started context:" + applicationContext);
            }
        }
    }
}
于 2015-04-27T18:44:35.107 に答える
4

springboot v1.2.2 の時点で、procrun を使用して、uber jar としてパッケージ化された Spring Boot アプリケーションをシャットダウンするクリーンな方法はありません。これは他の人も同様に尋ねていることなので、次の問題に従ってください。

スプリングブートのメンテナーがそれを処理するかどうか、またはどのように処理するかは明らかではありません。それまでは、uber jar を解凍し、Spring Boot の JarLauncher を無視することを検討してください。

この質問に対する私の最初の回答(履歴で表示可能)は、機能するはずの方法を提案しました(そして、私はそう思った)が、JarLauncherでクラスローダーがどのように処理されるかによるものではありません。

于 2015-03-17T15:57:16.843 に答える
3

これに遭遇して共有したかったので、しばらく前にこの問題を修正し、プルリクエストを発行しました。 https://github.com/spring-projects/spring-boot/pull/2520

procrun を使用して開始/停止するようにマージされるまで、私のフォークされたバージョンを使用できます。

于 2015-08-18T11:33:50.340 に答える
2

winswには近づかないでください。これは .NET で作成されており、古い Windows について顧客の環境で多くの問題を経験しています。

私はNSSMをお勧めします。これは純粋な C を使用して作成されており、すべての古い Windows で問題なく使用できました。それは同じ機能とそれ以上のものを持っています...

batch script (.bat)これを使用する方法のサンプルを次に示します。

rem Register the service
nssm install my-java-service "C:\Program Files\Java\jre1.8.0_152\bin\java.exe" "-jar" "snapshot.jar"
rem Set the service working dir
nssm set my-java-service AppDirectory "c:\path\to\jar-diretory"
rem Redirect sysout to file
nssm set my-java-service AppStdout "c:\path\to\jar-diretory\my-java-service.out"
rem Redirect syserr to file
nssm set my-java-service AppStderr "c:\path\to\jar-diretory\my-java-service.err"
rem Enable redirection files rotation
nssm set my-java-service AppRotateFiles 1
rem Rotate files while service is running
nssm set my-java-service AppRotateOnline 1
rem Rotate files when they reach 10MB
nssm set my-java-service AppRotateBytes 10485760
rem Stop service when my-java-service exits/stop
nssm set my-java-service AppExit Default Exit
rem Restart service when my-java-service exits with code 2 (self-update)
nssm set my-java-service AppExit 2 Restart
rem Set the display name for the service
nssm set my-java-service DisplayName "My JAVA Service"
rem Set the description for the service
nssm set my-java-service Description "Your Corp"
rem Remove old rotated files (older than 30 days)
nssm set my-java-service AppEvents Rotate/Pre "cmd /c forfiles /p \"c:\path\to\jar-diretory\" /s /m \"my-java-service-*.*\" /d -30 /c \"cmd /c del /q /f @path\""
rem Make a copy of my-java-service.jar to snapshot.jar to leave the original JAR unlocked (for self-update purposes)
nssm set my-java-service AppEvents Start/Pre "cmd /c copy /y \"c:\path\to\jar-diretory\my-java-service.jar\" \"c:\path\to\jar-diretory\snapshot.jar\""
于 2018-02-05T19:29:52.677 に答える