Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Java Webフレームワークの現状 / java web framework

Naoki Kishida
October 27, 2024
10k

Java Webフレームワークの現状 / java web framework

2024-10-27に開催されたJJUG CCC 2024 Fallでの登壇資料です
https://ccc2024fall.java-users.jp/

Naoki Kishida

October 27, 2024
Tweet

More Decks by Naoki Kishida

Transcript

  1. 2024/10/27 2 自己紹介 • きしだ なおき • LINEヤフー • X(twitter):

    @kis • blog: きしだのHatena • (nowokay.hatenablog.com) • 「プロになるJava」というJavaの本を書いてます
  2. Webの処理 • 簡単なWebサーバー • フレームワークは このようなWebサーバーから アプリケーション固有部分を 分離拡張できるようにする 仕組み void

    main() throws Exception{ var server = new ServerSocket(8080); for (;;) { var soc = server.accept(); Thread.ofVirtual().start(() -> { try (soc; var isr = new InputStreamReader(soc.getInputStream()); var bur = new BufferedReader(isr); var w = new PrintWriter(soc.getOutputStream())) { // ヘッダーの解析 var line = bur.readLine(); if (line == null) return; // exit thread println("Connect from %s for %s".formatted(soc.getInetAddress(), line)); while (!bur.readLine().isEmpty()) {} // urlによって処理の振り分け var url = line.split(" ")[1]; var message = switch(url) { case "/hello" -> "Hello!!!"; case "/date" -> LocalDate.now(); default -> "It works!"; }; // ヘッダー出力 w.println(""" HTTP/1.1 200 OK content-type: text/html """); w.println(); // コンテンツ出力 w.println(""" <html><head><title>Hello</title></head> <body><h1>Hello</h1>%s</body></html> """.formatted(message)); } catch (IOException ex) { throw new UncheckedIOException(ex); } }); } }
  3. Web開発に必要な処理 • HTTP処理 • リクエスト処理 • ルーティング • レスポンス処理 •

    Webアプリケーション処理 • セッション • 認証/認可 • リソース管理 • サーバー管理 • ネットワーク管理 • 実行管理 • 設定 • モニタリング • 開発管理 • ビルド • デプロイ • テスト
  4. Web開発に必要な処理 • HTTP処理 • リクエスト処理 • ルーティング • レスポンス処理 •

    Webアプリケーション処理 • セッション • 認証/認可 • リソース管理 • サーバー管理 • ネットワーク管理 • 実行管理 • 設定 • モニタリング • 開発管理 • ビルド • デプロイ • テスト var server = new ServerSocket(8080); for (;;) { var soc = server.accept();
  5. Web開発に必要な処理 • HTTP処理 • リクエスト処理 • ルーティング • レスポンス処理 •

    Webアプリケーション処理 • セッション • 認証/認可 • リソース管理 • サーバー管理 • ネットワーク管理 • 実行管理 • 設定 • モニタリング • 開発管理 • ビルド • デプロイ • テスト Thread.ofVirtual().start(() -> {
  6. Web開発に必要な処理 • HTTP処理 • リクエスト処理 • ルーティング • レスポンス処理 •

    Webアプリケーション処理 • セッション • 認証/認可 • リソース管理 • サーバー管理 • ネットワーク管理 • 実行管理 • 設定 • モニタリング • 開発管理 • ビルド • デプロイ • テスト // 本来ならポート番号を設定可能に var server = new ServerSocket(8080);
  7. Web開発に必要な処理 • HTTP処理 • リクエスト処理 • ルーティング • レスポンス処理 •

    Webアプリケーション処理 • セッション • 認証/認可 • リソース管理 • サーバー管理 • ネットワーク管理 • 実行管理 • 設定 • モニタリング • 開発管理 • ビルド • デプロイ • テスト println("Connect from %s for %s".formatted(soc.getInetAddress(), line)); } catch (IOException ex) { throw new UncheckedIOException(ex); }
  8. Web開発に必要な処理 • HTTP処理 • リクエスト処理 • ルーティング • レスポンス処理 •

    Webアプリケーション処理 • セッション • 認証/認可 • リソース管理 • サーバー管理 • ネットワーク管理 • 実行管理 • 設定 • モニタリング • 開発管理 • ビルド • デプロイ • テスト // ヘッダーの解析 var line = bur.readLine(); if (line == null) return; // exit thread println("Connect from %s for %s".formatted(soc.getInetAddress(), line)); while (!bur.readLine().isEmpty()) {}
  9. Web開発に必要な処理 • HTTP処理 • リクエスト処理 • ルーティング • レスポンス処理 •

    Webアプリケーション処理 • セッション • 認証/認可 • リソース管理 • サーバー管理 • ネットワーク管理 • 実行管理 • 設定 • モニタリング • 開発管理 • ビルド • デプロイ • テスト // urlによって処理の振り分け var url = line.split(" ")[1]; var message = switch(url) { case "/hello" -> "Hello!!!"; case "/date" -> LocalDate.now(); default -> "It works!"; };
  10. Web開発に必要な処理 • HTTP処理 • リクエスト処理 • ルーティング • レスポンス処理 •

    Webアプリケーション処理 • セッション • 認証/認可 • リソース管理 • サーバー管理 • ネットワーク管理 • 実行管理 • 設定 • モニタリング • 開発管理 • ビルド • デプロイ • テスト // ヘッダー出力 w.println(""" HTTP/1.1 200 OK content-type: text/html """); w.println(); // コンテンツ出力 w.println(""" <html><head><title>Hello</title></head> <body><h1>Hello</h1>%s</body></html> """.formatted(message));
  11. Web開発に必要な処理 • HTTP処理 • リクエスト処理 • ルーティング • レスポンス処理 •

    Webアプリケーション処理 • セッション • 認証/認可 • リソース管理 • サーバー管理 • ネットワーク管理 • 実行管理 • 設定 • モニタリング • 開発管理 • ビルド • デプロイ • テスト
  12. 15 フレームワークの種類 • HTTP処理を行う • →の部分を書きやすくする • 大きく3種類 • 宣言形式

    • 命令形式 • コンポーネント形式 var message = switch(url) { case "/hello" -> "Hello!!!"; case "/date" -> LocalDate.now(); default -> "It works!"; };
  13. 宣言形式 • アノテーションを使って宣言的に設定を行う。主流。 • Spring Web • JAX-RS • Jakarta

    EEではJakarta RESTful Web Servicesで略称なし • Micronaut • サーブレット
  14. 宣言形式 • だいたい似てる(アノテーション以外は同じコード) import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class

    HelloController { @GetMapping(value = "/hello", produces = "text/plain") public String hello() { return "Hello Spring Boot!!"; } } import jakarta.ws.rs.*; import jakarta.ws.rs.core.MediaType; @Path("/hello") public class HelloController { @GET @Produces(MediaType.TEXT_PLAIN) public String hello() { return "Hello JAX-RS!!"; } } import io.micronaut.http.MediaType; import io.micronaut.http.annotation.*; @Controller("/hello") public class HelloController { @Get @Produces(MediaType.TEXT_PLAIN) public String hello() { return "Hello Micronaut!!"; } }
  15. 命令形式 • 命令的にルーティングや処理を設定していく • Javalin • Helidon SE • だいたい似ている

    import io.helidon.webserver.WebServer; void main() { WebServer.builder() .port(8080) .routing(b -> b.get("/hello", (req, res) -> res.send("Hello Helidon!")) .get("/date", (req, res) -> res.send(LocalDate.now().toString())) .get("/*", (req, res) -> res.send("It Works!"))) .build().start(); } import io.javalin.Javalin; void main() { Javalin.create() .get("/hello", ctx -> ctx.result("Hello Javalin!")) .get("/date", ctx -> ctx.result(LocalDate.now().toString())) .get("/*", ctx -> ctx.result("It works!!")) .start(8080); }
  16. JSF • Java + Facelets(XHTML) • JavaはPOJO • 制御にクセがある v<f:view>

    <h:form> <div> <h:inputText id="in" value="#{helloBean.input}"/> <h:commandButton value="Hello" actionListener="#{helloBean.go()}"> <f:ajax execute="in" render="out"/> </h:commandButton> </div> <h:outputLabel id="out" value="#{helloBean.message}"/> </h:form> </f:view> import jakarta.enterprise.context.RequestScoped; import jakarta.inject.Named; @Named @RequestScoped public class HelloBean { // 実際にはそれぞれのsetter/getterが必要 private String message = "Hello!!!"; private String input = ""; public void go() { message = "hello " + input; } }
  17. ZK • Java + ZUL(XML) • Javaでコンポーネントのモデル管理 public class HelloComposer

    extends SelectorComposer<Component>{ @Wire private Label output; @Wire private Textbox input; @Listen("onClick = #exec") public void go() { output.setValue(input.getValue()); } } <zk> <window title="My Page" border="normal" apply="com.example.demo.HelloComposer"> It works!! <vlayout> <hlayout> <textbox id="input"/> <button id="exec" label="Go"/> </hlayout> <label id="output" value="hello"/> </vlayout> </window> </zk>
  18. Vaadin • すべてJavaで記述 @Component @Route("") public class MainView extends VerticalLayout{

    public MainView() { TextField textField = new TextField("Enter text"); Span label = new Span("Hello"); Button button = new Button("Go"); button.addClickListener(e -> label.setText(textField.getValue())); add(textField, button, label); } }
  19. 埋め込みサーバー • クラウドの隆盛 • 供給側:スレッド性能の頭打ちにより多サーバー化 • 需要側:4Gとスマホでトラフィックの増大 • ひとつのWebアプリを多数のサーバーで動かしてスケールアウト •

    サーブレットコンテナが不適合 • サーバーインストールやデプロイは ただ開発を面倒にするだけ • Spring Bootでのサーバー埋め込み • フレームワークのフルスタック化
  20. Dockerとマイクロサービス • プロセッサのさらなる多コア化 • 数十コアをいかすのに多数のVMを使うと無駄 • プロセスIDなどOSリソースだけ仮想化したコンテナの出現 • サーバープロセスの柔軟な運用が可能に •

    機能ごとにサーバーをわけて、負荷の高い機能に多くのサーバーリソースを振分け • マイクロサービス • JVM、サーブレットやSpring DIの起動速度が問題に • サーブレットに依存せずコンパイル時にDIを解決するQuarkusやMicronaut • 障害時の柔軟性も大切に • 障害が起きる前提の運用
  21. Java EEの凋落 • 1つのアプリケーションサーバーに多数のアプリケーションをデ プロイするJava EEのモデルはクラウドに合わなかった • 2013年にリリースされたJava EE 7はクラウドを考慮したもの

    とは言い難かった • その後もJava EE 8の開発は進まず • Java EEアプリケーションサーバーの高度な機能がKubernetes で代替される • Java EEの強みが失われていく
  22. Java EEガーディアンズとJakarta EE • Java EE 8を進めないオラクルへの不満から2016年にJava EE ガーディアンズが立ち上がる •

    2017年、Java EE 8のリリースとともにEclipse財団へ移管 • Javaの名前が使えなくなるため、Jakarta EEに
  23. MicroProfileのAPI • Telemetry • サーバー状態の取得・提供 • OpenAPI • API仕様記述 •

    RestClient • API呼び出し • Config • 設定 • Fault Tolerance • 耐障害性機能 • タイムアウト/リトライ/サーキットブレイカー • JWT Authentication • JSON Web Tokenによる認証 • Health • アプリケーションの稼働確認
  24. Jakarta EE 10 • 2022年にリリース • Java EE 7から9年 •

    Java EE 8は小変更 • Jakarta EE 9はパッケージ変更 • Core Profileの導入 • サーブレット非依存 Updated Not Updated New