1. Java Servle についてのあれやこれや
今日知り合いに質問されました。「ServletはJavaではないの?」。はい。いわゆるJava=Java SEではなく、エンタープライズ向けのJava EE の一部としして整理されているので、「Java言語」 を学習している間は出てくることはありません。ただ。今日までのJavaにとってもこれからのJava にとっても重要な技術であるため理解しておくことはとてもいいことです。
1-1. 成立時の状況
Java Servlet の仕様策定次期は1990年代の後半です。当時、広く普及し始めたインターネットで動的なコンテンツをどの様に生成するかが業界全体の課題でした。当時の主流はCGIを利用してhttp通信を引き込み、Perlやその他の言語に処理させるというものでした。この手法にはいくつかの課題があります。
- HTTPリクエストごとにプロセスが立ちあがり処理するため、PID限界にすぐに達する。
- プロセスの起動コストがかかり、ディスクI/O待ちが発生する。
この課題を解決するのがServletです。Servletは常駐プロセスとして起動し稼動し続けます。多数のHTTPリクエストを同時並列で処理することは通常のHTTPサーバと同様ですが、単一のプロセスでスレッドとして稼動します。これにより先ほどの2点の課題がすっと消え去るのです。
- 単一のプロセスとして動作するためPID枯渇を招くことはない。
- 常時起動しているため、処理開始までのオーバーヘッドがかからない。
- Java言語であるため動作する環境を選ばない。Windows/Linux/HP/BSDなんでもござれ。
こういった特製と、時代のニーズに後押しされてサーブレットは一気に普及しました。
1-2 Servletって何をするの?
大きく二つの役割を担います。
- ブラウザ等からのHTTPリクエストの内容をJavaのオブジェクトに変換して、適切なユーザプログラムを呼び出す。
- ユーザの生成したデータをHTTPの返却電文として加工してリクエストもとに返却する。
少し実際のコードを使って説明しましょう。
public class MyServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
try ( PrintWriter out = response.getWriter()) {
out.println("<!DOCTYPE html>");
out.println("<html>");
out.println("<head>");
out.println("<title>Servlet MyServlet</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>Servlet MyServlet </h1>");
out.println("</body>");
out.println("</html>");
}
}
}
これは本当に単純なServletです。動作の概要を説明します。
public class MyServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
…
すこしづつ解読しましょう。
public class MyServlet extends HttpServlet
このクラスがServletクラスであることを示します。Servletコンテナは特定URLに対するHTTP GETアクセスが発生するとこのメソッドを呼び出します。
(HttpServletRequest request
ブラウザからのリクエスト情報をrequestとして渡すので必要なら使ってね。
HttpServletResponse response)
ブラウザに対する応答はこのクラスに教えてあげてね。
続きをみてみましょう。
response.setContentType("text/html;charset=UTF-8");
HTTP応答ののContextTypeに text/html;charset=UTF-8 を
設定するよ。
try ( PrintWriter out = response.getWriter()) {
responsはJavaVMの外のリソースなので返答を返すために、Streamに対して書き出すためのWriterを取り出すよ。今後はこのWriterにHTML を出力するよ。
out.println("<!DOCTYPE html>");
out.println("<html>");
out.println
着々とHTMLを出力するよ
実行結果
このサーブレットをTomcatで起動後、ブラウザでアクセスすると以下のような画面になります。
これだけだとちょっとわからないので
C:\Users\shupe>curl http://localhost:8080/MyServlet --verbose
* Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /MyServlet HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/8.0.1
> Accept: */*
>
< HTTP/1.1 200
< Content-Type: text/html;charset=UTF-8
< Content-Length: 130
< Date: Sun, 30 Apr 2023 15:16:27 GMT
<
<!DOCTYPE html>
<html>
<head>
<title>Servlet MyServlet</title>
</head>
<body>
<h1>Servlet MyServlet</h1>
</body>
</html>
* Connection #0 to host localhost left intact
ユーザープログラマの書いた情報以外も見事に埋められていることがわかります。このように、ユーザの関心事=HTMLの内容だけをユーザが明示的に書き、その他のめんどくさいお約束事はServletコンテナが勝手に埋め込んでくれるのがServletの特徴です。
今回は、超簡単に「動的??」って感じのサイトですが、たとえばDBへのSQL発行結果等をout.print()
で埋め込むことで、作成するサイトを動的に変更することができるのです。
1-3 Servletの課題とその解決
シンプルで割と便利なServletですが。やはり課題もありました。
- かっこいいデザインを作りにくい
- プログラマとデザイナの作業分離がしにくい(全部ロジックで書くから)
このあたりが当時の課題です。このあたりの課題感から、JSP/JSFとデザイン/実装分離が進んでいくんですが。それはまた別のお話ということで。
1-5 Servletは廃れたの?
全く廃れていません。むしろ。JSP/JSFは廃れてしまうけど、Servletは今後も利用され続けるといった方が正しいです。
というのも、前述のとおり、Httpリクエストを引き込んで、ユーザープログラマに渡し、ユーザープログラマはHttpレスポンスを生成して返すというモデルはいわゆるWeb APIを実装するのに大変都合がいいからです。
皆さんご存知Java API実装の一つであるSpringBoot も実際のHTTPの受け口はServletを利用しています。
HTMLに限らず。ただレスポンスを文字列編集して返却するというシンプルな動作が、世代を超えて応用的に利用されやすい特性となっているんだと思います。
まとめ
- SevletはJava SE の一部ではないよ
- Sevletの使い方はメッチャ簡単だよ
- Sevletはこれからも使い続けていくよ
こんなお話でした。