今回から何回かに分けて、Java界隈で人気らしい「Spark Framework」の使い方について書いていきたいと思います。
Spark Frameworkの公式ページはこちら -> Spark Framework: An expressive web framework for Kotlin and Java
SparkやマイクロWebサービスがどんなものかとかは、公式ページやQiitaの他の方の記事におまかせして、ここでは私なりのSparkの使い方を解説していきます。
今回使用するライブラリ
- spark-core 2.7.1
- spark-debug-tools 0.5
Hello World!
実装
では、さっそくSparkの使い方を見ていきましょう。
まずは公式アナウンスのとおりPOMファイルを記述します。
- pom.xml
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>com.sparkjava</groupId>
<artifactId>spark-core</artifactId>
<version>2.7.1</version>
</dependency>
</dependencies>
続いて、アプリのエントリーポイントを作成します。
- Application.java
import static spark.Spark.get;
public class Application {
public static void main(String[] args) {
// getメソッドの第一引数にはリクエストをマッピングするパス、第二引数にはリクエストを処理するハンドラを記述します。
get("/", (req, res) -> "hello world!");
}
}
ハンドラはRoute
インターフェイスを実装して作成しますが、@FunctionalInterface
なのでJava 8以降なら例のようにラムダ式で実装することができます。寄り道してRoute
インターフェイスのシグネチャを見てみましょう。
@FunctionalInterface
public interface Route {
Object handle(Request request, Response response) throws Exception;
}
Route
インターフェイスはリクエストとレスポンスを引数にとり、レスポンスボディを返却するよう実装します。
ここでいうリクエストとレスポンスはSpark独自の型で、HttpServletRequest
なんかとは異なります。
実行
さて、実装したアプリを起動してみましょう。
私はEclipseで実装しているので、「実行」->「Javaアプリケーション」->「作成したクラスのMainメソッド」と選択していきます。
実際の起動時に
java
コマンドでMainメソッドを指定するのはナンセンスですね。
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
実行すると、コンソールに上記のようなログが出力されると思いますが、ちゃんと起動しています。
SparkはロギングをSLF4Jで実施していますが、今回のアプリではロギング実装ライブラリを入れていないので、警告が出ています。
実行したアプリにCURLでアクセスしてみましょう。もちろんブラウザでURLを叩いてもOKです。
$ curl -s http://localhost:4567
hello world!
なんとも味気ないですが、「Hello World!」が出力されました。
Sparkアプリのデバッグ
Eclipseでデバッグするから問題ないぜ!という方もいると思いますが、
Sparkでは公式でデバッグツールが提供されています。
spark-debug-toolsは、以下のように簡単に適用できます。
- pom.xml
<dependency>
<groupId>com.sparkjava</groupId>
<artifactId>spark-debug-tools</artifactId>
<version>0.5</version>
</dependency>
- Application.java
import static spark.Spark.get;
import static spark.debug.DebugScreen.enableDebugScreen;
public class Application {
public static void main(String[] args) {
// (1) `enableDebugScreen`メソッドでデバッグ画面が有効になります。
enableDebugScreen();
// (2) ハンドラで例外(`Exception`)がスローされると、自動的にデバッグ画面に遷移するようになります。
get("/", (req, res) -> { throw new Exception("error"); });
}
}
デバッグ画面はFree Markerで実装されているようです。たまにデバッグ画面のレンダリングに失敗することもあるので、Free Markerの知識があると使いやすいと思います。
Sparkプロジェクトテンプレートの作成
ここまでの動作確認を踏まえて、Sparkアプリのプロジェクトテンプレートを作成しておきます。
- pom.xml
<properties>
<!-- (1) Settings -->
<java.version>1.8</java.version>
<encoding>UTF-8</encoding>
<spark.mainClass>io.github.yoshikawaa.spark.sample.Application</spark.mainClass>
<!-- (2) Maven Properties -->
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
<project.build.sourceEncoding>${encoding}</project.build.sourceEncoding>
<project.reporting.outputEncoding>${encoding}</project.reporting.outputEncoding>
<exec.mainClass>${spark.mainClass}</exec.mainClass>
</properties>
<build>
<!-- (3) Create Fat Jar -->
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>${spark.mainClass}</mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<!-- (4) Spark -->
<dependency>
<groupId>com.sparkjava</groupId>
<artifactId>spark-core</artifactId>
<version>2.7.1</version>
</dependency>
<dependency>
<groupId>com.sparkjava</groupId>
<artifactId>spark-debug-tools</artifactId>
<version>0.5</version>
</dependency>
<!-- (5) Logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.25</version>
</dependency>
<!-- (6) Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.20</version>
<scope>provided</scope>
</dependency>
</dependencies>
no. | description |
---|---|
(1) | プロジェクトのセッティングを集約定義します。基本的に、こことdependencies だけ変えればそれなりにアプリが作れることを意識します。 |
(2) | Mavenプラグインにセットするプロパティを定義します。 * maven.compiler.source , maven.compiler.target は最初に出てきた、Java 8コンパイルするための定義です。* project.build.sourceEncoding , project.reporting.outputEncoding はソースやJavaDocをエンコードするための定義で、Eclipseでの文字化け防止に役立ちます。* exec.mainClass はExec Maven Pluginで実行するときのMainクラスを指定するための定義で、Mavenからアプリを実行するときに使います。 |
(3) | パッケージングしたJarを実行するときにjava コマンドでMainクラスを指定しなければならない!、実行してみたけど依存ライブラリが足りない!などの問題をクリアするため、Maven Assembly Pluginで依存関係も含めてまとめたJarを作成します。 |
(4) |
spark-core とspark-debug-tools への依存関係を定義します。 |
(5) | デフォルトロギング実装としてslf4j-simple への依存関係を定義します。ロギングについては、次回以降解説します。 |
(6) | 今回触れませんでしたが、コーディングサポートのためlombok への依存関係を定義します。 |
- Application.java
import static spark.Spark.get;
import static spark.debug.DebugScreen.enableDebugScreen;
public class Application {
public static void main(String[] args) {
// configure application.
enableDebugScreen();
// configure routes.
get("/", (req, res) -> "hello world!");
}
}
まとめ
Sparkはスタートアップまでが非常に早いので、簡単に動くアプリをさっと作りたいときには重宝しそうです。
とはいえ、それなりにまともなアプリを作ろうと思うと、自分で考えなきゃいけないところがあり、Spring Bootのように「あまり仕組みを知らなくてもフルセットのアプリが作れる」という簡単さはないところですね。
次回からは、テーマを決めて実装方法を解説していきたいと思います。