LoginSignup
57

More than 5 years have passed since last update.

Spring Bootでコマンドラインアプリを作る時の注意点

Posted at

次の点に注意しましょう。

  • spring-boot-starter-webは使わない
  • 本処理の実装でCommandLineRunnerは使わない(私見)

spring-boot-starter-webは使わない

コマンドラインアプリを作る時にpom.xmlのdependencyにspring-boot-starter-webを使ってはいけません。

spring-boot-starter-webを使ってしまうと、自分ではコマンドラインアプリを作ってるつもりでも、起動するとWebサーバーが立ち上がってしまいます。ログを注意して見ればWebサーバーを起動しているのがわかるはずです。

コマンドラインアプリケーションの場合はspring-boot-starterを使いましょう。

pom.xmlの雛形は次のようになります。

pom.xml
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.2.5.RELEASE</version>
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

本処理の実装でCommandLineRunnerは使わない(私見)

※これは個人的な見解で、はっきりと断定できるものではありません。

よく見かけるサンプルでは、メインクラスをCommandLineRunnerの実装クラスとして作成して、runメソッドにアプリの本処理を書いています。
自分も最初はこういう作り方をするものだと思ってました。

Application.java
@SpringBootApplication
public class Application implements CommandLineRunner {
    public static void main(String[] args) {
        System.out.println("main()");
        SpringApplication.run(Application.class, args);
    }
    @Override
    public void run(String... args) throws Exception {
        System.out.println("処理開始");
        //アプリの処理
        System.out.println("処理終了");
    }
}

しかし、この使い方だとJUnitを使う時に問題が生じます。

次のような空のテストメソッドを作成して実行してみます。

ApplicationTest.java
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
public class ApplicationTest {
    @Test
    public void test() {
    }
}
実行結果
:
処理開始
処理終了
:

なんということでしょう。呼び出してもいないアプリの本処理が実行されてしまうではありませんか。
これではRepositoryクラスなどのコンテナからインスタンスを取得してテストするケースで毎回本処理が実行されてしまい、厄介なことになります。

なので、本処理の実装にCommandLineRunnerを使うのはやめて、次のようにmainメソッドから本処理を自分で呼び出すようにしましょう。

Application.java
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        System.out.println("main()");
        try (ConfigurableApplicationContext ctx = SpringApplication.run(Application.class, args)) {
            Application app = ctx.getBean(Application.class);
            app.run(args);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public void run(String... args) throws Exception {
        System.out.println("処理開始");
        //アプリの処理
        System.out.println("処理終了");
    }
}

ちなみにSpringBootのドキュメントには次のように書かれています。

22.6 Using the CommandLineRunner

If you want access to the raw command line arguments, or you need to run some specific code once the SpringApplication has started you can implement the CommandLineRunner interface. The run(String…​ args) method will be called on all Spring beans implementing this interface.

CommandLineRunnerを使うのは、

  • コマンドライン引数を参照したいとき
  • 起動時に一度だけ実行したい処理があるとき

と書いてあり、どちらかというと補助的な処理を実装するのが目的のように読み取れます。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
57