Google Guice 5 web
?
3 Web 和 Servlet
3.1 快速开始
我们从一个例子开始Guice Web的开发。
?
首先准备我们的环境,由于是web开发,因此我们需要guice-servlet的jar包。log4j不是必须的,只是为了方便日志记录而已(Guice内部是使用jdk内部的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的模块注入。
2?
3?????@Override
4?????protected?Injector?getInjector()?{
5?????????return?Guice.createInjector(new?ServletModule());
6?????}
7?}
8?
继续在web.xml中添加东西。
<listener>????<listener-class>cn.imxylz.study.guice.web.MyGuiceServletContextListener</listener-class>
</listener>
?
显然我们需要将某个PATH映射到一个Servlet上,于是需要在ServletModule上做点事情。
?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?@Singleton2?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?}
?
注意,根据Guice的Servlet要求,每一个Servlet必须是单例的,因此这里强制加上@Singleton。
好了,我们来看看输出。

?3.2 注入服务
?当然了,既然是一个IOC的容器,那么在Guice中也是可以注入服务的。
?首先定义一个服务。
2?public?interface?HelloWorld?{
3?
4?????void?execute()?throws?IOException;
5?}
6?
接着是服务的实现,注意在我们的服务中需要request和response对象,并且我们的服务假定是与request绑定的,采用@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中可以采用如下实现。
?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对象获取我们的服务,注意我们没有将HttpServletRequest和HttpServletResponse手动注入到我们的服务中。
好了,我们再来看看输出。可以看到我们的对象是与request绑定,同一个request使用的同一个HelloWorld服务,不同的request那么是同一个session获取的服务也是不一样的。

?老实说,Guice关于WEB的东西其实大概就这么多。其它的关于多规则匹配顺序,正则表达式匹配等等其实不谈也罢,都很弱,用处不大。
?3.3 整合Struts 2
Guice可以与Struts 2整合,当然了理论上可以与其它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只是为了记录日志方便而已。
首先定义一个服务,服务很简单输出服务器的状态。
2?
3?????String?getStatus();
4?}
5?
2?
3?????public?String?getStatus()?{
4?????????return?"I'am?running.";
5?????}
6?}
7?
然后写一个Module绑定服务及其实现,当然如果偷懒可以使用@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级别的对象绑定访问次数。
?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出场了。
?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?
可以看到我们很简单的服务又被Guice给入侵了,所以说Guice对我们业务逻辑的侵入是很大,估计这也是很多程序员不愿意推广Guice的一个原因吧。
要写的Java代码就这么多,剩下的就是一堆的配置了。
首先web.xml中配置struts2的filter,注意这里我们没必要再配置一个guice的listener了,因为在guice的struts2的插件中已经配置一个ServletModule了。
?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了。
?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的注入过程。
当然了我们需要配置一个Struts2的action类cn.imxylz.study.guice.web.struts2.AccessStatusAction,访问地址access-status.action正确的时候渲染access-status.jsp页面。
?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?
所有的工作就完成了,我们看看浏览器中的渲染结果。

?即使如此,Guice整合Struts 2还是比较弱的。