ソフトウェアエンジニアの雑記

日々思ったことをまとめます

Javaをスクリプト言語っぽくするJBang その3(SpringBootでAPIサーバを作る,実用プロジェクトに変換する)

Javaスクリプト言語っぽくするJBangその3です。今回はSpringBootを起動してみようと思います。その1その2の内容は説明しませんので、下記からみてください。

k-sasaki.net

k-sasaki.net

想定シナリオ

ちょっとSpringBootとかで試したいことがあるときやAPIサーバの挙動とかを軽くテストしたいときに使う感じです。モノリスなどで大きい場合はちょっとした検証をするにもDBやRedisなどが必要になったり、ユニットテストを書かないといけなかったりちょっと面倒です。それをJBangが解決してくれます。

成果物

成果物は下記になります。一つずつ説明します。(追加説明を希望の場合はコメントにお願いします。)

Gistにもあげておきます。

https://gist.github.com/ko-sasaki/f38dfe9fc7146268520cf72f333565e5

///usr/bin/env jbang "$0" "$@" ; exit $?

package api;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

//JAVA 21+
//DEPS org.springframework.boot:spring-boot-starter-web:3.5.0
//FILES application.yml
//REPOS central,jitpack,google


@SpringBootApplication
@RestController
public class SpringBootSample {

    @Value("${sample.message}")
    private String message;

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

    /**
     * 固定メッセージを返却する.
     */
    @GetMapping("/hello")
    public String hello() {
        return "Hello, World!";
    }

    /**
     * URLパスで指定された文字列でメッセージを置換して返却する.
     */
    @GetMapping("/hello/{name}")
    public String hello(@PathVariable String name) {
        return "Hello, {name}!".replace("{name}", name);
    }
    
    /**
     * application.ymlのメッセージを表示する
     */
    @GetMapping("/hello/message")
    public String message() {
        return message;
    }
}

application.ymlの中身は下記

server:
  port: 8081

sample:
  message: Hello, Application Yaml!

ファイル作成

jbang init を使用して新規にファイルを作成します。

jbang init api/SpringBootSample.java

上記でファイルが作成されます。

パッケージ設定

SpringBootはルートパッケージですとDB設定などが動きだしてしまうので、テスト用のパッケージを指定します。

package api;

Javaバージョン

Java21以上で動作するように設定します。

//JAVA 21+

Javaがインストールされていない場合は下記のコマンドを入力してみてください。

// JBangを使用する場合
jbang jdk install 21

or 

// SDKMANを使用する場合
sdk install java 21.0.7-tem

依存関係

SpringBootをAPIサーバとして動かすのはこの1行だけで十分になります。

//DEPS org.springframework.boot:spring-boot-starter-web:3.5.0

なんかすごいですよね。この1行だけでSpringBootが起動できるなんて。

ファイル

//FILESで起動時に読み込むファイルを指定する。

//FILES application.yml

Javaコード

Javaコードの部分は、SpringBootのRestControllerのときに書くものを1ファイルにまとめたものです。いくつかのパターンで書いてあります。

@SpringBootApplication
@RestController
public class SpringBootSample {

    @Value("${sample.message}")
    private String message;

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

    @GetMapping("/hello")
    public String hello() {
        return "Hello, World!";
    }

    @GetMapping("/hello/{name}")
    public String hello(@PathVariable String name) {
        return "Hello, {name}!".replace("{name}", name);
    }
    
    @GetMapping("/hello/message")
    public String message() {
        return message;
    }
}

実行

Webアプリケーションでも実行方法は変わりません。下記のコマンドで実行します。

$jbang api/SpringBootSample.java

[jbang] Building jar for SpringBootSample.java...

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/

 :: Spring Boot ::                (v3.5.0)

2025-06-14T10:11:49.229+09:00  INFO 60388 --- [           main] api.SpringBootSample                     : Starting SpringBootSample using Java 21.0.7 with PID 60388 (/Users/kohei.sasaki/.jbang/cache/jars/SpringBootSample.java.be468baacb1ab8033bb744d7e1c4d7073e1736db3075b9bb1af7e20d0c22a440/SpringBootSample.jar started by kohei.sasaki in /Users/kohei.sasaki/git/jbang-sample)
2025-06-14T10:11:49.230+09:00  INFO 60388 --- [           main] api.SpringBootSample                     : No active profile set, falling back to 1 default profile: "default"
2025-06-14T10:11:49.664+09:00  INFO 60388 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port 8081 (http)
2025-06-14T10:11:49.674+09:00  INFO 60388 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2025-06-14T10:11:49.674+09:00  INFO 60388 --- [           main] o.apache.catalina.core.StandardEngine    : Starting Servlet engine: [Apache Tomcat/10.1.41]
2025-06-14T10:11:49.706+09:00  INFO 60388 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2025-06-14T10:11:49.706+09:00  INFO 60388 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 449 ms
2025-06-14T10:11:49.911+09:00  INFO 60388 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port 8081 (http) with context path '/'
2025-06-14T10:11:49.917+09:00  INFO 60388 --- [           main] api.SpringBootSample                     : Started SpringBootSample in 0.938 seconds (process running for 1.114)
2025-06-14T10:12:09.050+09:00  INFO 60388 --- [nio-8081-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2025-06-14T10:12:09.050+09:00  INFO 60388 --- [nio-8081-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2025-06-14T10:12:09.050+09:00  INFO 60388 --- [nio-8081-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 0 ms

これで起動完了です。

curlコマンドでテストしてみます。

$ curl localhost:8081/hello
Hello, World!

$ curl localhost:8081/hello/hogehoge
Hello, hogehoge!

$ curl localhost:8081/hello/message
Hello, Application Yaml!

ちゃんと期待したものが応答されました。

Gistを経由してのコード共有

上記のコードをGistにあげておきます。jbangコマンドにGistのURLを指定すると自動でダウンロードして、依存解決をして実行してくれます。とても便利です。

$ jbang https://gist.github.com/ko-sasaki/f38dfe9fc7146268520cf72f333565e5

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/

 :: Spring Boot ::                (v3.5.0)

2025-06-14T14:50:06.953+09:00  INFO 6158 --- [           main] api.SpringBootSample                     : Starting SpringBootSample using Java 21.0.7 with PID 6158 (/Users/kohei.sasaki/.jbang/cache/jars/SpringBootSample.java.6ed9516f48ab6c188d73ce5f1a848c811e4640775b1e8eea6cc1305d8c9a6c69/SpringBootSample.jar started by kohei.sasaki in /Users/kohei.sasaki/git/jbang-sample)
2025-06-14T14:50:06.954+09:00  INFO 6158 --- [           main] api.SpringBootSample                     : No active profile set, falling back to 1 default profile: "default"
2025-06-14T14:50:07.358+09:00  INFO 6158 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port 8081 (http)
2025-06-14T14:50:07.368+09:00  INFO 6158 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2025-06-14T14:50:07.368+09:00  INFO 6158 --- [           main] o.apache.catalina.core.StandardEngine    : Starting Servlet engine: [Apache Tomcat/10.1.41]
2025-06-14T14:50:07.395+09:00  INFO 6158 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2025-06-14T14:50:07.395+09:00  INFO 6158 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 415 ms
2025-06-14T14:50:07.574+09:00  INFO 6158 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port 8081 (http) with context path '/'
2025-06-14T14:50:07.579+09:00  INFO 6158 --- [           main] api.SpringBootSample                     : Started SpringBootSample in 0.846 seconds (process running for 1.019)

とても簡単ですね。

プロジェクトに変換する

ここまでプロジェクトができたら、jbangではなく通常のプロジェクトに変換したくなってきます。JBangではexportコマンドがあり、それを実現できます。exportのコマンドはExecutableJar形式、Gradle形式、Maven形式など色々な形式で出力できます。今回はGradle形式で出力してみます。

$ jbang export gradle --output export_dir api/SpringBootSample.java

export_dirディレクトリの中身をみてみます。

$ tree export_dir
export_dir/
├── build.gradle
└── src
    └── main
        ├── java
        │   └── api
        │       └── SpringBootSample.java
        └── resources
            └── application.yml

jbangで書いた構成がそのまま出力されています。build.gradleも生成されており、実際にビルドや実行などができます。

まとめ

JBangでSpringBootのWebアプリケーションサーバの起動がすぐできました。Gist経由でコードの共有や実行まで確認できたり、exportコマンドでスムーズにプロジェクトに昇格できるようになっています。プロダクトエンジニアのことがよくわかっている、かなり気が利いているツールになっています。エコシステムとしても既存のものを最大限フル活用しており、独自仕様のようなものがコンパクトにまとまっています。チーム内でも広めたいですし、Javaエンジニアのみならず、Java初学者の方がもっと使ってくれたらと思います。

次回はAI系またはデバッグについて書こうと思います。