3 Web 和 Servlet
3.1 快速開始
我們從一個例子開始Guice Web的開發(fā)。
首先準(zhǔn)備我們的環(huán)境,由于是web開發(fā),因此我們需要guice-servlet的jar包。log4j不是必須的,只是為了方便日志記錄而已(Guice內(nèi)部是使用jdk內(nèi)部的logging包來完成日志記錄的)。
必可避免的要在web.xml中都一些手腳,這里先配置一個filter吧。
<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>
GuiceFilter中并沒有幫我們完成Guice的初始化工作,因此我們必須手動完成Guice的模塊注入。
1 public class MyGuiceServletContextListener extends GuiceServletContextListener {
2
3 @Override
4 protected Injector getInjector() {
5 return Guice.createInjector(new ServletModule());
6 }
7 }
8
繼續(xù)在web.xml中添加?xùn)|西。
<listener>
<listener-class>cn.imxylz.study.guice.web.MyGuiceServletContextListener</listener-class>
</listener>
顯然我們需要將某個PATH映射到一個Servlet上,于是需要在ServletModule上做點事情。
1 public class MyGuiceServletContextListener extends GuiceServletContextListener {
2
3 @Override
4 protected Injector getInjector() {
5 return Guice.createInjector(new ServletModule() {
6 protected void configureServlets() {
7 serve("/helloworld").with(HelloWorldServlet.class);
8 }
9 });
10 }
11 }
12
這里將/helloworld這個地址映射到HelloWorldServlet上。好吧,先寫個 “HelloWorld”的Servlet吧。
1 @Singleton
2 public class HelloWorldServlet extends HttpServlet{
3 private static final long serialVersionUID = 1L;
4 @Override
5 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException,
6 IOException {
7 resp.getWriter().append("Hello, guice! "+new Date());
8 }
9 }
注意,根據(jù)Guice的Servlet要求,每一個Servlet必須是單例的,因此這里強(qiáng)制加上@Singleton。
好了,我們來看看輸出。
3.2 注入服務(wù)
當(dāng)然了,既然是一個IOC的容器,那么在Guice中也是可以注入服務(wù)的。
首先定義一個服務(wù)。
1 @ImplementedBy(HelloWorldImpl.class)
2 public interface HelloWorld {
3
4 void execute() throws IOException;
5 }
6
接著是服務(wù)的實現(xiàn),注意在我們的服務(wù)中需要request和response對象,并且我們的服務(wù)假定是與request綁定的,采用@RequestScoped標(biāo)簽來標(biāo)識。
1 @RequestScoped
2 public class HelloWorldImpl implements HelloWorld {
3
4 private HttpServletRequest request;
5 private HttpServletResponse response;
6 @Inject
7 public HelloWorldImpl(HttpServletRequest request, HttpServletResponse response) {
8 super();
9 this.request = request;
10 this.response = response;
11 }
12
13 public void execute() throws IOException{
14 String name=request.getParameter("user");
15 if(name==null||name.length()<1)name="Guest";
16 response.getWriter().append(String.format("Hello, %s. %s -> sessionId=%s,hashCode=%d "n", name,new Date(),request.getSession().getId(),hashCode()));
17 }
18
19 }
20
然后在我們的Servlet中可以采用如下實現(xiàn)。
1 @Singleton
2 public class HelloWorldServlet extends HttpServlet{
3 private static final long serialVersionUID = 1L;
4 @Inject
5 private Injector inj;
6 @Override
7 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException,
8 IOException {
9 inj.getInstance(HelloWorld.class).execute();
10 inj.getInstance(HelloWorld.class).execute();
11 }
12 }
這里我們自動注入Injector對象,然后通過Inject對象獲取我們的服務(wù),注意我們沒有將HttpServletRequest和HttpServletResponse手動注入到我們的服務(wù)中。
好了,我們再來看看輸出。可以看到我們的對象是與request綁定,同一個request使用的同一個HelloWorld服務(wù),不同的request那么是同一個session獲取的服務(wù)也是不一樣的。
老實說,Guice關(guān)于WEB的東西其實大概就這么多。其它的關(guān)于多規(guī)則匹配順序,正則表達(dá)式匹配等等其實不談也罷,都很弱,用處不大。
3.3 整合Struts 2
Guice可以與Struts 2整合,當(dāng)然了理論上可以與其它MVC框架整合,只是Guice官方提供了一個Struts 2的插件。
首先看看依賴的jar包,我們盡可能的少用jar包。
aopalliance-1.0.jar是guice-servlet依賴的,因此guice需要aopalliance/guice/guice-servlet/guice-struts2-plugin等包,struts2啟動依賴commons-logging/freemarker/ognl/struts2-core/xwork等jar包。lo4j只是為了記錄日志方便而已。
首先定義一個服務(wù),服務(wù)很簡單輸出服務(wù)器的狀態(tài)。
1 public interface Service {
2
3 String getStatus();
4 }
5
1 public class ServiceImpl implements Service {
2
3 public String getStatus() {
4 return "I'am running.";
5 }
6 }
7
然后寫一個Module綁定服務(wù)及其實現(xiàn),當(dāng)然如果偷懶可以使用@ImplementedBy,這里為了說明如果在配置文件中配置Module,所以單寫一個Module。
1 public class ServiceModule implements Module {
2 @Override
3 public void configure(Binder binder) {
4 binder.bind(Service.class).to(ServiceImpl.class);
5 }
6 }
然后寫一個SessionScope級別的對象綁定訪問次數(shù)。
1 @SessionScoped
2 public class AccessCounter {
3
4 private AtomicInteger count = new AtomicInteger(0);
5
6 public int visit() {
7 return count.incrementAndGet();
8 }
9
10 @Override
11 public String toString() {
12 return String.format("AccessCounter#%s:%d", this.hashCode(), count.get());
13 }
14 }
15
好了,我們的Servlet出場了。
1 package cn.imxylz.study.guice.web.struts2;
2
3 import com.google.inject.Inject;
4
5 public class AccessStatusAction {
6
7 final AccessCounter counter;
8 final Service service;
9 String message;
10
11 @Inject
12 public AccessStatusAction(AccessCounter counter, Service service) {
13 this.counter = counter;
14 this.service = service;
15 }
16
17 public String execute() {
18 return "success";
19 }
20
21 public int getCount() {
22 return counter.visit();
23 }
24
25 public String getStatus() {
26 return service.getStatus();
27 }
28
29 public String getMessage() {
30 return message;
31 }
32
33 public void setMessage(String message) {
34 this.message = message;
35 }
36 }
37
可以看到我們很簡單的服務(wù)又被Guice給入侵了,所以說Guice對我們業(yè)務(wù)邏輯的侵入是很大,估計這也是很多程序員不愿意推廣Guice的一個原因吧。
要寫的Java代碼就這么多,剩下的就是一堆的配置了。
首先web.xml中配置struts2的filter,注意這里我們沒必要再配置一個guice的listener了,因為在guice的struts2的插件中已經(jīng)配置一個ServletModule了。
1 <?xml version="1.0" encoding="UTF-8"?>
2 <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
4 version="2.5">
5
6 <display-name>guice</display-name>
7 <description>xylz study project - guice</description>
8
9 <filter>
10 <filter-name>guiceFilter</filter-name>
11 <filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
12 </filter>
13 <filter-mapping>
14 <filter-name>guiceFilter</filter-name>
15 <url-pattern>/*</url-pattern>
16 </filter-mapping>
17 <filter>
18 <filter-name>struts2</filter-name>
19 <filter-class>org.apache.struts2.dispatcher.FilterDispatcher
20 </filter-class>
21 </filter>
22 <filter-mapping>
23 <filter-name>struts2</filter-name>
24 <url-pattern>/*</url-pattern>
25 </filter-mapping>
26 <!-- listener>
27 <listener-class>cn.imxylz.study.guice.web.MyGuiceServletContextListener</listener-class>
28 </listener -->
29 </web-app>
30
下面該配置struts.xml了。
1 <!DOCTYPE struts PUBLIC
2 "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
3 "http://struts.apache.org/dtds/struts-2.0.dtd">
4
5 <struts>
6
7 <constant name="guice.module" value="cn.imxylz.study.guice.web.struts2.ServiceModule"/>
8
9 <package name="default" extends="struts-default">
10 <action name="access-status"
11 class="cn.imxylz.study.guice.web.struts2.AccessStatusAction">
12 <result>access-status.jsp</result>
13 </action>
14 </package>
15
16 </struts>
17
在這里先配置我們的Module,我們的Module就是完成Guice的注入過程。在guice的Struts2插件中類com.google.inject.struts2.GuiceObjectFactory有以下邏輯:
@Inject(value = "guice.module", required = false)
void setModule(String moduleClassName) {
try {
// Instantiate user's module.
@SuppressWarnings({"unchecked"})
Class<? extends Module> moduleClass =
(Class<? extends Module>) Class.forName(moduleClassName);
this.module = moduleClass.newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
這段邏輯就是完成我們Module的注入過程。
當(dāng)然了我們需要配置一個Struts2的action類cn.imxylz.study.guice.web.struts2.AccessStatusAction,訪問地址access-status.action正確的時候渲染access-status.jsp頁面。
1 <%@ taglib prefix="s" uri="/struts-tags" %>
2
3 <html>
4 <body>
5 <h1>Access Status</h1>
6 <h3><b>Access in this session:</b>
7 <s:property value="count"/></h3>
8
9 <h3><b>Status:</b>
10 <s:property value="status"/></h3>
11
12 <h3><b>Message:</b>
13 <s:property value="message"/></h3>
14 <h4><%="sessionId="+session.getId()%></h4>
15 </body>
16 </html>
17
所有的工作就完成了,我們看看瀏覽器中的渲染結(jié)果。
即使如此,Guice整合Struts 2還是比較弱的。
上一篇:Google Guice 入門教程05 - AOP(面向切面編程)
下一篇:Google Guice 入門教程07 - 整合第三方組件(01)
©2009-2014 IMXYLZ
|求賢若渴