オープンソースの中を覗いて勉強になることがある。
Google guice の Servlet を利用する時。
web.xml の、<servlet-mapping>を Javaで記述というと、そんなことして何の意味がある!と思うだろうが、
実際に実行すると意外な機能に気づく。
GuiceServletContextListener を継承したリスナを用意して、web.xml に以下のように
記述する。
<listener>
<listener-class>sample.labo.MyListener</listener-class>
</listener>
<servlet-mapping>の記述を web.xml から排除する。
================ MyListener.java ================
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.servlet.GuiceServletContextListener;
public class MyListener extends GuiceServletContextListener{
@Override
protected Injector getInjector(){
return Guice.createInjector(new MyServletModule());
}
}
================ MyServletModule.java ================
import com.google.inject.servlet.ServletModule;
public class MyServletModule extends ServletModule{
@Override
protected void configureServlets(){
serve("/aa/*").with(AaServlet.class);
serve("/bb/*").with(BbServlet.class);
}
}
これで、URI パターンに対する実行サーブレットを定義する
これだけを見ると単にJavaで定義するようになる効果しか見えないが、、、
サーブレットを実行時に、
上記の extends ServletModule の威力が発揮されて、各サーブレットから実行する
doGet や doPost で任意ユーザーインタフェースのDI生成したインスタンスで、
HttpServletRequest 等を自動的に注入できる。
================ AaServlet.java ================
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.google.inject.Injector;
import com.google.inject.Singleton;
// クラス宣言に、Singleton アノテーションは必須
@Singleton
public class AaServlet extends HttpServlet{
private static final long serialVersionUID = 1L;
private Injector injector;
@Override
public void init(ServletConfig config) throws ServletException{
super.init(config);
this.injector = (Injector)config.getServletContext()
.getAttribute("com.google.inject.Injector");
}
@Override
protected void doGet(HttpServletRequest request,HttpServletResponse response)
throws ServletException,IOException{
Dispatcher dispatch = this.injector.getInstance(ASampleDoGet.class);
dispatch.exec();
}
@Override
protected void doPost(HttpServletRequest request,HttpServletResponse response)
throws ServletException,IOException{
//
}
}
↑↑↑Dispatcher という任意インターフェース←ASampleDoGet.class クラスDI生成させて実行
================ ASampleDoGet.java ================
import java.io.IOException;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import com.google.inject.Inject;
import com.google.inject.servlet.RequestParameters;
public class ASampleDoGet implements Dispatcher{
@Inject private HttpServletRequest request;
@Inject private HttpServletResponse response;
@Inject @RequestParameters private Map<String, String[]> params;
@Inject private HttpSession session;
@Override
public void exec(){ // doGet で実行
// private ローカル変数を利用できる。
}
}
====================================================
これは、com.google.inject.servlet.GuiceServletContextListener のソースを覗くことで、
サーブレットコンテキストに Injector が、ServletContext#setAttribute で格納されてる
ことが判りユーザのサーブレットの public void init(ServletConfig config) で
サーブレットコンテキストより、extends ServletModule でリスナに作らせた
Injector を取得できるのである。
このInjector を利用することが、HttpServletRequest のバインド定義を
有効にさせている。