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
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;
@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;
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コードの部分は、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系またはデバッグについて書こうと思います。