Help us understand the problem. What is going on with this article?

Spring Boot でコマンドラインツールを作る個人的ベストプラクティス

More than 1 year has passed since last update.

TL; DR

  • CommandLineRunner は使うけど、CommandLineRunner#run(String... args) は、Application 起動完了前に呼び出されてしまうため、初期化に読み替えて、サブクラスでオーバーライドする
  • 複数のコマンドは @ConditionalOnProperty(name = "command", havingValue = "xxx") で起動し分けるとよさげ。

Motivation

Spring boot 、Web サーバーをさくっと上げるところから本格的なサービスにも使えて、Batch もある程度あります。

Web サービスに使ってるロジックや、Batch 用ロジックなんかを手元で実行したかったり(何かおこったときの再実行とか。。。。)にそのまま実行できる .jar を作っておくと便利なのですが、やり方が色々あって悩む事多しの状況だったのでメモです。

Sampleコード全部

package echo;

import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.stereotype.Service;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@SpringBootApplication
public class EchoApplication {
    public abstract static class Command implements CommandLineRunner {
        public final void run(final String... args) throws Exception {
            log.debug("Initialize started on {}", getClass());
            // 実際、CommandLineRunner#run(String... args) は、Application 起動完了前に呼び出されてしまう。
            // ここでは初期化に読み替えて、サブクラスでオーバーライドする
            init(args);
        }

        void init(final String... args) throws Exception {
            // 生引数を引き取って何かする
        }

        /**
         * サブクラスで実装
         * @throws Exception
         */
        abstract void execute() throws Exception;
    }

    public static void main(final String... args) throws Exception {
        try (ConfigurableApplicationContext context = SpringApplication.run(EchoApplication.class, args)) {
            context.getBean(Command.class).execute();
            // Command を取って実行
        }
    }

    @Service
    @ConditionalOnProperty(name = "command", havingValue = "foo")
    public static class FooFeature extends Command {
        @Override
        void execute() throws Exception {
            log.info("Foo");
        }
    }

    @Service
    @ConditionalOnProperty(name = "command", havingValue = "bar")
    public static class BarFeature extends Command {
        @Override
        void execute() throws Exception {
            log.info("Bar");
        }
    }
}

実行するとこんな感じに

% java -jar xxxx.jar --command=foo
2017-09-09 20:58:48.464  INFO 20274 --- [           main] echo.EchoApplication      : Started EchoApplication in 2.895 seconds (JVM running for 3.342)
2017-09-09 20:58:48.464  INFO 20274 --- [           main] echo.EchoApplication      : Foo

% java -jar xxxx.jar --command=bar
2017-09-09 20:58:48.464  INFO 20274 --- [           main] echo.EchoApplication      : Started EchoApplication in 2.895 seconds (JVM running for 3.342)
2017-09-09 20:58:48.464  INFO 20274 --- [           main] echo.EchoApplication      : Bar

その他

WebApp とまとめる

WebApp, CommandLine Tool をまとめたいときは、command line tool として実行するときは
--spring.main.web-environment=false で Web Context が起動しなくなります。

command profile を作って application.yml に書いておくと楽かも

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした