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 に書いておくと楽かも