如果讀者對於Guice沒有大體的瞭解,可以參考本人的另一篇Guice基礎文章
Guice 提供了一個完整的體系使得我們在web應用中也可以使用它作爲依賴注入的工具.
爲什麼使用 Guice :
使用Guice的好處:
- 構造函數注入
- 類型安全的, 方便的配置方式(只需要在web.xml中進行很少的配置)
- 模塊化
- Guice AOP
同時, Guice並不會改變標準servlet的生命週期
如何配置呢?
在開始之前首先獲取最新的 guice-servlet.jar.
小編用maven做,所以這塊如果讀者使用其他方式需要根據自己的情況進行配置.這裏貼上小編的 maven 文件內容:
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<version>4.0</version>
</dependency>
<dependency>
<groupId>com.google.inject.extensions</groupId>
<artifactId>guice-servlet</artifactId>
<version>4.0</version>
</dependency>
在web.xml中配置GuiceFilter
過濾器:
在所有依賴包都配置好之後,我們需要做的第一件事是配置GuiceFilter
. 這個過濾器重新路由所有的客戶端請求.
<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>
安裝ServletModule
在完成上面的操作之後,接下來要做的事情是安裝ServletModule
Guice.createInjector(new ServletModule());
這個模塊是用來設置請求和會話範圍(scopes),同時提供一個配置你的過濾器和servlet的方法. 一個不錯的建議是在一個ServletContextListener
中進行,當然你也可以在其他你需要該注入器(injector)的地方.
Guice Servlet提供了一個GuiceServletContextListener
,我們可以繼承該類實現自己的ServletContextListener
:
public class MyGuiceServletConfig extends GuiceServletContextListener {
@Override
protected Injector getInjector() {
return Guice.createInjector(new ServletModule());
}
}
然後在web.xml中配置該listener.然後當Servlet 容器啓動Web 應用時,該監聽器便會被執行.我們的ServletModule
被安裝.
<listener>
<listener-class>com.up.MyGuiceServletConfig</listener-class>
</listener>
Binding Language
我們可以將ServletModule
看做一個代碼形式的web.xml文件.過濾器和servlet可以通過簡單的調用一些java api 實現.下面看一個簡單的例子:
Guice.createInjector(..., new ServletModule() {
@Override
protected void configureServlets() {
serve("/*").with(MyServlet.class);
filter("/*").through(MyFilter.class);
}
}
serve("/*").with(MyServlet.class);
等價於
<servlet>
<servlet-name>MyFilter</servlet-name>
<servlet-class>com.up.servlet.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyFilter</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
filter("/*").through(MyFilter.class);
等價於
<filter>
<filter-name>MyFilter</filter-name>
<filter-class>com.up.filter.MyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>MyFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Note: 每個 servlet 或者 filter 需要是單例的.如果你不能直接註解該類,那麼你需要使用bind(..).in(Singleton.class)
. Guice servlet不支持SingleThreadModel
可用的注入:
安裝了ServletModule
之後我可方便的注入一些servlet體系中的類.
@RequestScoped
class SomeNonServletPojo {
@Inject
SomeNonServletPojo(HttpServletRequest request, HttpServletResponse response, HttpSession session) {
...
}
}
請求和響應是當前http請求作用域。同樣的http會話對象是當前用戶會話作用域。除此之外你也可以使用綁定註釋@RequestParameters注入當前ServletContext和請求參數如下:
@Inject @RequestParameters Map<String, String[]> params;
這裏必須是Map<String, String[]>
,因爲http允許多個value對應於同一個key.
Note: 如果你想給一個大作用域的對象注入一個請求作用域或者會話作用域的對象, 你應該使用Provider<T>
多對一映射
我們可以將多個 url 映射到相同的 servlet.
serve("*.html", "/my/*").with(MyServlet.class);
該方法對於過濾器也同樣適用.
正則表達式映射
我們也可以使用正則表達式方式映射 url 到特定的 servlet 或 filter.
serveRegex("(.)*ajax(.)*").with(MyAjaxServlet.class)
上述實例會將所有包含 “ajax” 的 URI 映射到 MyAjaxServlet
.
初始化參數
在有 web.xml 時,我們可以通過配置<init-param>
給 servlet 或 filter 傳入初始化參數. Guice Servlet 中完成該任務只需要在配置該 servlet 或 filter 時傳入一個Map<String, String>
實例就ok了.
Map<String, String> params = new HashMap<String, String>();
params.put("coffee", "Espresso");
params.put("site", "google.com");
serve("/*").with(MyServlet.class, params)
綁定Key
你也可以不綁定特定的實現類,取而代之的是綁定一個接口,然後通過 Guice 注入特定的實現類.
filter("/*").through(Key.get(Filter.class, Fave.class));
這裏的Filter.class
是 Servlet API javax.seervlet.Filter
, Fave.class
是一個自定義的綁定註解.
然後在你自己的模塊中將特定的filter綁定到該接口.
bind(Filter.class).annotatedWith(Fave.class).to(MyFilterImpl.class);
注入injector
你可以在任何時刻取得injector對象,只需要像下面這樣一行代碼就可以了.
@Singleton
public class MyServlet extends HttpServlet {
@Inject private Injector injector;
...
}
// elsewhere in ServletModule
serve("/myurl").with(MyServlet.class);
恭喜你,到此你可以開始你自己的 Guice Servlet 之旅了.