Guice & Servlet
GuiceとServletの連携というのをやってみます。
今回試すのは、Guiceで管理するオブジェクトに「RequestScoped」「SessionScoped」というスコープを設定することです。
Guiceのスコープの範囲で、「リクエスト」と「セッション」が使えるようになります。
GuiceとServletの連携では、この他にも幾つかの機能が得られるようです。(それはまた後ほど)
資料がないのでAPIとにらめっこでやります。
Tomcat 5.5を使いました。
まずは以下のライブラリを利用します。
ディレクトリ構成
webapps
└Guice
├WEB-INF
│├classes
││└(クラス生成先)
│├src
││└(作成ソースファイル)
│└lib
│ ├guice-servlet-1.0.jar
│ └guice-1.0.jar
└Hello.jsp
作成するファイル | 役割 |
---|---|
net.kronos_jp.guice.servlet.HelloService | インジェクトされるサービスオブジェクト、Guiceのアノテーションでリクエストスコープのオブジェクトに設定します。 |
net.kronos_jp.guice.servlet.HelloWorld | サーブレットを継承。Guiceから受け取ったHelloServiceのフィールドを書き換えます。その後Hello.jspへ転送します。 |
Hello.jsp | HelloWorldサーブレットから転送を受け付けてGuiceからHelloServiceオブジェクトを取得。メッセージを表示します。 |
web.xml | Guiceが提供するFilterやサーブレットクラスを登録します。 |
web.xml
Guiceが提供するフィルター「GuiceFilter」を全てのリクエストに適用します。
このフィルターによって、Guice&Servletで機能する様々な仕組みが提供されます。
その他はHelloWorldサーブレットを登録してます。
<?xml version="1.0" encoding="SHIFT_JIS"?> <web-app version="2.4"> <filter> <filter-name>GuiceFilter</filter-name> <filter-class>com.google.inject.servlet.GuiceFilter</filter-class> </filter> <filter-mapping> <filter-name>GuiceFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <servlet> <servlet-name>helloworld</servlet-name> <servlet-class>net.kronos_jp.servlet.HelloWorld</servlet-class> </servlet> <servlet-mapping> <servlet-name>helloworld</servlet-name> <url-pattern>/hello/*</url-pattern> </servlet-mapping> </web-app>
HelloService.java
HelloServiceは、Guiceで管理するオブジェクトです。
@RequestScopedアノテーションが設定されていることで、リクエストスコープの間1つのインスタンスが使われます。
このほか、@SessionScopedアノテーションも提供されています。
package net.kronos_jp.servlet; import com.google.inject.servlet.RequestScoped; @RequestScoped public class HelloService { private String message; public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } }
HelloWorld.java
HelloWorld サーブレットは、GuiceからHelloServiceオブジェクトのインスタンスを取得し、
フィールド値を書き換えてHello.jspへ転送する役割を持っています。
package net.kronos_jp.servlet; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.*; import com.google.inject.*; import com.google.inject.servlet.ServletModule; public class HelloWorld extends HttpServlet{ @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Injector injector = Guice.createInjector(new ServletModule()); HelloService hello = injector.getInstance(HelloService.class); hello.setMessage("Hello Hello!"); request.getRequestDispatcher("Hello.jsp").forward(request,response); } }
Hello.jsp
HelloServiceがリクエストスコープのオブジェクトであるため、GuiceからHelloServiceオブジェクトを取得すると
先ほどHelloWorldサーブレットでフィールド値を書き換えたインスタンスが取得出来ます。
HelloServiceのインスタンスを取得してメッセージを表示しています。
<%@page import="net.kronos_jp.servlet.HelloService" %> <%@page import="com.google.inject.Guice" %> <%@page import="com.google.inject.servlet.ServletModule" %> <HTML> <BODY> <% HelloService hello = com.google.inject.Guice.createInjector(new ServletModule()).getInstance(HelloService.class); %> <B><%= hello.getMessage() %></B> </BODY> </HTML>
実行結果
http://localhost:8080/Guice/helloでHelloWorldサーブレットを起動すると「Hello Hello!」と表示されました。
リクエストスコープであることを確認したいならば以下のように試してみることができます。
HelloWorldサーブレットを実行した後で、同じブラウザを使ってhttp://localhost:8080/Guice/Hello.jspを直接実行したとしても、オブジェクトは生存しておらず「null」と表示されます。(別リクエストとなるため)
またstaticフィールドを使ったシングルトンでもないので、ブラウザのインスタンスをもう1つ起動して「HelloWorldサーブレット」と「Hello.jsp」を、それぞれ別々に実行したとしても、Hello.jspに直接アクセスしたほうでは、elloWorldサーブレットの影響を受けず、やはり「null」と表示されます。
@SessionScopedに切り替えるのも、1つの箇所を書き換えるだけです。
この場合、一度HelloWorldサーブレットを実行したブラウザでは「Hello.jsp」を直接表示してもメッセージが表示されます。