Slide 1

Slide 1 text

Webフレームワークの現状 2024-10-27 JJUG CCC 2024 Fall LINEヤフー きしだ なおき

Slide 2

Slide 2 text

2024/10/27 2 自己紹介 ● きしだ なおき ● LINEヤフー ● X(twitter): @kis ● blog: きしだのHatena ● (nowokay.hatenablog.com) ● 「プロになるJava」というJavaの本を書いてます

Slide 3

Slide 3 text

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(""" Hello

Hello

%s """.formatted(message)); } catch (IOException ex) { throw new UncheckedIOException(ex); } }); } }

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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()) {}

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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

Hello

%s """.formatted(message));

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

Webフレームワークの変化 ● サーブレットコンテナ ● 埋め込みサーバー ● Docker ● サーバレス

Slide 14

Slide 14 text

サーブレットコンテナ ● サーブレットコンテナと呼ばれるWebサーバーに アプリケーションを配備する ● コンピュータが低性能だったため、ひとつのサーバープロセスで 複数のアプリケーションを動かす(メモリが128MBとか) ● Strutsに始まるフレームワークはサーブレットのラッパ ● HTTP処理のみ行う ● 開発や運用が面倒

Slide 15

Slide 15 text

15 フレームワークの種類 ● HTTP処理を行う ● →の部分を書きやすくする ● 大きく3種類 ● 宣言形式 ● 命令形式 ● コンポーネント形式 var message = switch(url) { case "/hello" -> "Hello!!!"; case "/date" -> LocalDate.now(); default -> "It works!"; };

Slide 16

Slide 16 text

宣言形式 ● アノテーションを使って宣言的に設定を行う。主流。 ● Spring Web ● JAX-RS ● Jakarta EEではJakarta RESTful Web Servicesで略称なし ● Micronaut ● サーブレット

Slide 17

Slide 17 text

宣言形式 ● だいたい似てる(アノテーション以外は同じコード) 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!!"; } }

Slide 18

Slide 18 text

命令形式 ● 命令的にルーティングや処理を設定していく ● 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); }

Slide 19

Slide 19 text

コンポーネント形式 ● クライアントとサーバー処理をまとめたUIコンポーネントを 組み立ていく ● サーバーサイドだけでUI含めて実装 ● それぞれ特徴的 ● JSF ● ZK ● Vaadin ● 有償コンポーネントで会社が成り立っている

Slide 20

Slide 20 text

JSF ● Java EE / Jakarta EE標準 ● Jakarta EEではJakarta Faces

Slide 21

Slide 21 text

JSF ● Java + Facelets(XHTML) ● JavaはPOJO ● 制御にクセがある v
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; } }

Slide 22

Slide 22 text

ZK ● Java + ZUL(XML) ● Javaでコンポーネントのモデル管理 public class HelloComposer extends SelectorComposer{ @Wire private Label output; @Wire private Textbox input; @Listen("onClick = #exec") public void go() { output.setValue(input.getValue()); } } It works!!

Slide 23

Slide 23 text

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); } }

Slide 24

Slide 24 text

埋め込みサーバー ● クラウドの隆盛 ● 供給側:スレッド性能の頭打ちにより多サーバー化 ● 需要側:4Gとスマホでトラフィックの増大 ● ひとつのWebアプリを多数のサーバーで動かしてスケールアウト ● サーブレットコンテナが不適合 ● サーバーインストールやデプロイは ただ開発を面倒にするだけ ● Spring Bootでのサーバー埋め込み ● フレームワークのフルスタック化

Slide 25

Slide 25 text

サーバー埋め込みによるビルド多様化 ● WAR一択からの変化 ● fat-jar ● JVM一体パッケージ ● Dockerコンテナ化 ● ネイティブコンパイル

Slide 26

Slide 26 text

Dockerとマイクロサービス ● プロセッサのさらなる多コア化 ● 数十コアをいかすのに多数のVMを使うと無駄 ● プロセスIDなどOSリソースだけ仮想化したコンテナの出現 ● サーバープロセスの柔軟な運用が可能に ● 機能ごとにサーバーをわけて、負荷の高い機能に多くのサーバーリソースを振分け ● マイクロサービス ● JVM、サーブレットやSpring DIの起動速度が問題に ● サーブレットに依存せずコンパイル時にDIを解決するQuarkusやMicronaut ● 障害時の柔軟性も大切に ● 障害が起きる前提の運用

Slide 27

Slide 27 text

サーバレスとネイティブイメージ ● 機能ごとにサーバーをわけるマイクロサービスをつきつめると リクエストハンドラ単体が1プロセスに切り分けられる ● サーバレス ● クラウド対応CGI ● JVMの起動時間だけではなくJIT最適化の時間も問題に ● 1リクエスト処理するとJITの前にプロセスが終わる ● GraalVMでのネイティブコンパイル ● Project Leydenで標準化

Slide 28

Slide 28 text

Java標準は? ● Java EEの凋落 ● Java EEガーディアンズとJakarta EE ● MicroProfile ● Jakarta EE 10

Slide 29

Slide 29 text

Java EEの凋落 ● 1つのアプリケーションサーバーに多数のアプリケーションをデ プロイするJava EEのモデルはクラウドに合わなかった ● 2013年にリリースされたJava EE 7はクラウドを考慮したもの とは言い難かった ● その後もJava EE 8の開発は進まず ● Java EEアプリケーションサーバーの高度な機能がKubernetes で代替される ● Java EEの強みが失われていく

Slide 30

Slide 30 text

Java EEガーディアンズとJakarta EE ● Java EE 8を進めないオラクルへの不満から2016年にJava EE ガーディアンズが立ち上がる ● 2017年、Java EE 8のリリースとともにEclipse財団へ移管 ● Javaの名前が使えなくなるため、Jakarta EEに

Slide 31

Slide 31 text

MicroProfile ● Java EEのクラウド対応、特にマイクロサービス対応に期待でき ない状況でも強い要求があり、Java EEガーディアンズにも参加 しているメンバーにより2016年にMicroProfileが策定される ● 監視や耐障害性が中心 ● Jakarta EE Core Profileベース

Slide 32

Slide 32 text

MicroProfileのAPI ● Telemetry ● サーバー状態の取得・提供 ● OpenAPI ● API仕様記述 ● RestClient ● API呼び出し ● Config ● 設定 ● Fault Tolerance ● 耐障害性機能 ● タイムアウト/リトライ/サーキットブレイカー ● JWT Authentication ● JSON Web Tokenによる認証 ● Health ● アプリケーションの稼働確認

Slide 33

Slide 33 text

Jakarta EE 10 ● 2022年にリリース ● Java EE 7から9年 ● Java EE 8は小変更 ● Jakarta EE 9はパッケージ変更 ● Core Profileの導入 ● サーブレット非依存 Updated Not Updated New

Slide 34

Slide 34 text

まとめ ● プログラムとしてWebフレームワークがどういう位置付けか知る とコントロールしやすくなる ● 変化の経緯を知っておくと機能の意味がわかりやすい ● フレームワークの機能からアプリケーションに必要な要素を知る