A little bit of everything

情報系大学院生の備忘録

Spring Bootでコンソールアプリケーションを作る方法

1. はじめに

Spring Boot で、コンソールアプリケーションを作る方法のメモです。
Spring Boot はWebアプリケーションを作るためによく使われますが、コンソールアプリケーションも作れます。
今回は、コンソール上で標準出力に「Hello World!」と出力して終了するだけの単純なアプリを作ります。

完成品のサンプルアプリは、Githubで公開しています。
github.com

Webアプリを作る場合とほとんど変わりませんが、1箇所だけ、Webアプリを作る場合と違う書き方をする必要があります。

2. 前提

  • Mavenがインストールされていること(バージョンは3以上なら何でも可)
    • ※ Gradleの方は読み替えてください。
  • Javaがインストールされていること(バージョンは8以上なら何でも可)

3. 作り方

3.1 プロジェクトの雛形を作る

Spring Initializrで雛形を作る(https://start.spring.io/)。


もしくは私がGithubで公開しているものを clone しても問題ありません。
git clone https://github.com/YuukiYg/sample-springboot-console


3.2 pomを編集する

dependency に「spring-boot-starter-web」や「spring-boot-starter-web-services」が入っている場合は消してください。
これが入っていると、起動した際に、Webアプリとして認識されてしまい、組み込みTomcatが立ち上がってしまいます。

コンソールアプリを作る場合は、「spring-boot-starter」を使用します。
dependencies の例は以下のとおりです。

pom.xml 内のdependenciesタグの例

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>


3.3 コーディング

コーディングしていきます。
今回は、コンソールアプリケーションだけど、DIを使ってSpringっぽく作りたいと思います。ビジネスロジックと、それを呼び出すmainメソッドの依存関係を、DIで取り除くようなイメージです。

ビジネスロジックのインタフェースを作成

ビジネスロジックは、sayHello() という単純なメソッドだけを持つものにしたいと思います。

HelloComponent.java

public interface HelloService {
    public void sayHello();
}


ビジネスロジックのインタフェースの実装クラスを作成

先ほど作ったインタフェースの実装部分です。
sayHello()メソッドは、単純に標準出力に「Hello World!」と出力するだけのものです。

ポイントとしては、@Component アノテーションをクラスに付与してください。

こうすることで、アプリケーション起動時のコンポーネントスキャンによって、このクラスが自動でインスタンス化(JavaBean化)され、SpringのDIコンテナに登録され、別クラス(後述のmainクラス)から使用できるようになります。

※DIコンテナは、ApplicationContextとも言います。

HelloComponentImpl.java

@Component
public class HelloServiceImpl implements HelloService{

    @Override
    public void sayHello() {
        System.out.println("Hello World!");
    }
}


■mainクラスの作成

最後に、mainメソッドを持つクラスを作成します(作成というより、Spiring Initializrを使用したのであれば、クラスの雛形が自動生成されているはずです)。

サンプルコードは以下のとおりです。ポイントは後述します。

SampleSpringbootConsoleApplication.java

@SpringBootApplication  // ポイント1
public class SampleSpringbootConsoleApplication {
    public static void main(String[] args) {
        // ポイント2
        ConfigurableApplicationContext context = SpringApplication.run(SampleSpringbootConsoleApplication.class, args);

        // ポイント3
        HelloService service = context.getBean(HelloService.class);

        // ポイント4
        service.sayHello();
    }
}

このクラスのポイントは以下のとおりです。

ポイント1

クラスに@SpringBootApplicationを付与する(というより、自動生成されているはずです)。

ポイント2

mainメソッド内で、DIコンテナ(アプリケーションコンテキスト)を取得します。

ここが、一般的にSpring BootでWebアプリケーションを作るときと異なるポイントです。

※このように書く理由は後述します。

ポイント3

取得したDIコンテナから、ビジネスロジックのJavaBeanであるHelloServiceのBeanを取得します。

ポイント4

取得したJavaBeanのビジネスロジックを呼び出します。

参考:ポイント2のように書く理由

例えばよくあるWebアプリだと、

SpringApplication.run(SampleSpringbootConsoleApplication.class, args);

というふうに実行するだけで、組み込みTomcatが立ち上がり、Webサーバとして実行されます(Webサーバが待ち受け状態に入ります)。

しかし今回はコンソールアプリケーションなので、main()メソッドの実行とともにアプリケーションが立ち上がり、ビジネスロジックを実行した後、mainメソッドの終了とともにアプリケーションが終了するように作りたいと思います。

そうなると問題なのが、mainメソッドを持つクラス内で@Injectや@AutowiredによってBeanを受け取ることができないことです。
つまり、以下のように書くことはできないのです。

@SpringBootApplication
public class SampleSpringbootConsoleApplication {

    // このように書いても、mainメソッド内から使用することができない。
    @Inject
    static HelloService helloService;

    public static void main(String[] args) {
        SpringApplication.run(SampleSpringbootConsoleApplication.class, args);

        // ここでヌルポで落ちる。
        helloService.sayHello();
    }
}

したがって、mainメソッドの中でDIコンテナを取得し、取得したDIコンテナからJavaBeanを取得し、mainメソッドの中でそのJavaBeanを使う、というふうに作る必要があります。

3.4 アプリケーションを実行

SampleSpringbootConsoleApplicationをSpring Bootアプリケーションとして実行すれば、以下のようなログが出て、「Hello World!」と出力されているのが確認できると思います。

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.2.0.RELEASE)

2019-11-04 15:16:44.124  INFO 65664 --- [           main] y.s.s.SampleSpringbootConsoleApplication : Starting SampleSpringbootConsoleApplication on Yuuki.local with PID 65664 (/Users/Yuuki/development/sample-springboot-console/target/classes started by Yuuki in /Users/Yuuki/development/sample-springboot-console)
2019-11-04 15:16:44.127  INFO 65664 --- [           main] y.s.s.SampleSpringbootConsoleApplication : No active profile set, falling back to default profiles: default
2019-11-04 15:16:44.593  INFO 65664 --- [           main] y.s.s.SampleSpringbootConsoleApplication : Started SampleSpringbootConsoleApplication in 0.845 seconds (JVM running for 1.482)
Hello World!

4.さいごに

以上が、Spring Boot でコンソールアプリケーションを作る方法のメモです。
もっと重厚なアプリケーションを作りたい場合は、Serviceインタフェースと、Serviceインタフェースの実装クラスに、ロジックを書いていけば良いと思います。