xylz,imxylz

关注后端架构、中间件、分布式和并发编程

   :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  111 随笔 :: 10 文章 :: 2680 评论 :: 0 Trackbacks

4 整合第三方组件

在《Google Guice 入门教程06 – Web 和Servlet》 中我们看到了Guice 整合Struts 2的应用。本章节继续讨论Guice整合其它第三方组件的应用。

本章节重点谈Guice与DWR和Spring的整合。

4.1 整合DWR

DWR作为Ajax远程调用的服务端得到了很多程序员的追捧,在DWR的2.x版本中已经集成了Guice的插件。

老套了,我们还是定义一个HelloWorld的服务吧,哎,就喜欢HelloWorld,不怕被别人骂!


1 public interface HelloWorld {
2 
3     String sayHello();
4 
5     Date getSystemDate();
6 }
7 

然后写一个简单的实现吧。


 1 public class HelloWorldImpl implements HelloWorld {
 2 
 3     @Override
 4     public Date getSystemDate() {
 5         return new Date();
 6     }
 7 
 8     @Override
 9     public String sayHello() {
10         return "Hello, guice";
11     }
12 }
13 

然后是与dwr有关的东西了,我们写一个dwr的listener来注入我们的模块。


 1 package cn.imxylz.study.guice.web.dwr;
 2 
 3 import org.directwebremoting.guice.DwrGuiceServletContextListener;
 4 
 5 /**
 6  * @author xylz (www.imxylz.cn)
 7  * @version $Rev: 105 $
 8  */
 9 public class MyDwrGuiceServletContextListener extends DwrGuiceServletContextListener{
10 
11     @Override
12     protected void configure() {
13         bindRemotedAs("helloworld", HelloWorld.class).to(HelloWorldImpl.class).asEagerSingleton();
14     }
15 }
16 

这里使用bindRemotedAs来将我们的服务开放出来供dwr远程调用。

剩下的就是修改web.xml,需要配置一个dwr的Servlet并且将我们的listener加入其中。看看全部的内容。


 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-dwr</display-name>
 7     <description>xylz study project - guice</description>
 8 
 9     <listener>
10         <listener-class>cn.imxylz.study.guice.web.dwr.MyDwrGuiceServletContextListener
11         </listener-class>
12     </listener>
13     <servlet>
14         <servlet-name>dwr-invoker</servlet-name>
15         <servlet-class>org.directwebremoting.guice.DwrGuiceServlet</servlet-class>
16         <init-param>
17           <param-name>debug</param-name>
18           <param-value>true</param-value>
19         </init-param>
20     </servlet>
21     <servlet-mapping>
22         <servlet-name>dwr-invoker</servlet-name>
23         <url-pattern>/dwr/*</url-pattern>
24     </servlet-mapping>
25 
26 </web-app>
27 

非常简单,也非常简洁,其中DwrGuiceServlet的debug参数只是为了调试方便才开放的,实际中就不用写了。

好了,看看我们的效果。

 1 <html>
 2 <head><title>dwr - test (www.imxylz.cn) </title>
 3   <script type='text/javascript' src='/guice-dwr/dwr/interface/helloworld.js'></script>
 4   <script type='text/javascript' src='/guice-dwr/dwr/engine.js'></script>
 5   <script type='text/javascript' src='/guice-dwr/dwr/util.js'></script>
 6   <script type='text/javascript'>
 7     var showHello = function(data){
 8         dwr.util.setValue('result',dwr.util.toDescriptiveString(data,1));   
 9     }
10     var getSystemDate = function(data){
11         dwr.util.setValue('systime',dwr.util.toDescriptiveString(data,2));   
12     }
13   </script>
14   <style type='text/css'>
15     input.button { border: 1px outset; margin: 0px; padding: 0px; }
16     span { background: #ffffdd; white-space: pre; padding-left:20px;}
17   </style>
18 </head>
19 <body onload='dwr.util.useLoadingMessage()'>
20     <p>
21     <h2>Guice and DWR</h2>
22         <input class='button' type='button' value="Call HelloWorld 'sayHello' service" onclick="helloworld.sayHello(showHello)" />
23         <span id='result' ></span>
24     </p>
25     <p>
26         <input class='button' type='button' value="Call HelloWorld 'getSystemDate' service" onclick="helloworld.getSystemDate(getSystemDate)" />
27         <span id='systime' ></span>
28     </P>
29 </body>
30 </html>

 

我们通过两个按钮来获取我们的远程调用的结果。

guice-dwr演示结果 我对DWR的认识也仅限于此就不献丑了。有兴趣的可以研究http://directwebremoting.org/dwr/

4.2 整合Spring

仍然使用我们的HelloWorld服务。


1 public interface HelloWorld {
2 
3     String sayHello(String user);
4 }
5 

1 public class HelloWorldImpl implements HelloWorld {
2 
3     @Override
4     public String sayHello(String user) {
5         return String.format("Welcome to Guice with spring, %1$s. Now is %2$tF %2$tH:%2$tM:%2$tS.", user,new Date());
6     }
7 }
8 

当然了,我们定义一个简单的spring配置文件,只有一个bean。

1 <?xml version="1.0" encoding="UTF-8"?>
2 <beans xmlns="http://www.springframework.org/schema/beans"
3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4     xsi:schemaLocation="http://www.springframework.org/schema/beans
5 http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
6     <bean id="helloworld" class="cn.imxylz.study.guice.spring.HelloWorldImpl"
7         scope="singleton" />
8 </beans>

 

然后看我们的Demo程序。


 1 public static void main(String[] args) {
 2 
 3     final ApplicationContext context = new ClassPathXmlApplicationContext("/applicationContext.xml", GuiceSpringDemo.class);
 4     Injector injector = Guice.createInjector(new AbstractModule() {
 5         protected void configure() {
 6           bind(BeanFactory.class).toInstance(context);
 7           bind(HelloWorld.class).toProvider(SpringIntegration.fromSpring(HelloWorld.class"helloworld"));
 8         }
 9       });
10     HelloWorld hw1 =injector.getInstance(HelloWorld.class);
11     String msg=hw1.sayHello("xylz");
12     System.out.println(msg);
13     HelloWorld hw2 =(HelloWorld)context.getBean("helloworld");
14     String msg2=hw2.sayHello("xylz");
15     System.out.println(msg2);
16     System.out.println(hw1==hw2);
17 }
18 

最后我们通过Injector和ApplicationContext都能够得到我们的服务,并且我们的服务hw1==hw2。

如果闲一个个服务的注入麻烦,这里还有一个简便的方法,一次将spring中的所有服务都注入。

final ApplicationContext context = new ClassPathXmlApplicationContext("/applicationContext.xml", GuiceSpringDemo.class);
        Injector injector 
= Guice.createInjector(new Module() {
            @Override
            
public void configure(Binder binder) {
                SpringIntegration.bindAll(binder, context);
            }
        });

 

但是Guice获取服务的方式就不一样了。

String msg=injector.getInstance(Key.get(HelloWorldImpl.class, Names.named("helloworld"))).sayHello("xylz");
System.out.println(msg);

这里我们不能getInstance(HelloWorld.class)来获取一个服务了,为什么呢?因为注入所有服务的时候,Guice并不能知道我们的服务是什么类型,于是将当作实际的类型注入了,另外由于spring允许一种类型的多个服务(bean)存在,所以自动注入的时候为了区分就需要带一个命名的注解,比如我们的helloworld,这个名称就是spring中的id。在Injector中为了获取一个带注解的类型服务,我们需要com.google.inject.Key<T>对象,此对象可以讲类型和注解关联起来,这样我们就能从Guice容器中获取一个服务了。

那如果我们想屏蔽真实的服务代码,也就是我们只是想客户端拿到HelloWorld服务而不是HelloWorldImpl实现怎么做?

目前只能在spring中使用代理服务。

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4     xsi:schemaLocation="http://www.springframework.org/schema/beans
 5 http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
 6     <bean id="helloworldTarget" class="cn.imxylz.study.guice.spring.HelloWorldImpl"
 7         scope="singleton" />
 8     <bean id="helloworld" class="org.springframework.aop.framework.ProxyFactoryBean">
 9         <property name="proxyInterfaces" value="cn.imxylz.study.guice.spring.HelloWorld" />
10         <property name="target" ref="helloworldTarget" />
11     </bean>
12 </beans>

然后我们在Guice中这样获取服务:

String msg=injector.getInstance(Key.get(HelloWorld.class, Names.named("helloworld"))).sayHello("xylz");
System.out.println(msg);

显然,如果客户端知道服务的实际类型并且知道spring中的id,那么仍然可以调用我们的服务,比如下面的例子:

String msg3=injector.getInstance(Key.get(HelloWorldImpl.class, Names.named("helloworldTarget"))).sayHello("xylz");
System.out.println(msg3);

 

上一篇:Google Guice 入门教程06 – Web 和 Servlet

下一篇:Google Guice 入门教程08 - 整合第三方组件(2)



©2009-2014 IMXYLZ |求贤若渴
posted on 2009-12-29 00:11 imxylz 阅读(27350) 评论(5)  编辑  收藏 所属分类: J2EEGoogle Guice

评论

# Guice与Spring整合的问题 2011-01-25 10:07 lxy
你好,我有一个Guice与Spring整合的问题想请教。
我有一个BlogDao数据访问接口,一个BlogService业务逻辑接口。
BlogDao的实现类为BlogDaoImpl,而BlogService的实现类为BlogServiceImpl。
然后进行如下绑定:

public class BlogModule extends AbstractModule {
protected void configure() {
ApplicationContext beanFactory = new ClassPathXmlApplicationContext("beans.xml");

bind(BeanFactory.class).toInstance(beanFactory);
bind(BlogDao.class).toProvider(fromSpring(BlogDao.class, "blogDaoImpl"));
bind(BlogService.class).toProvider(fromSpring(BlogService.class, "blogServiceImpl"));
}
}

测试类如下:
@RunWith(AtUnit.class)
@Container(Container.Option.GUICE)
@MockFramework(MockFramework.Option.JMOCK)
public class TestITest implements Module {
@Inject
BlogService blogService;
@Inject
BlogDao blogDao;

@Test
public void test() {
System.out.println(blogService);
System.out.println(blogDao);
}
}
这样可以正确打印得到对象。
然后在BlogServiceImpl里面定义BlogDao接口:如下:
@Service
public class BlogServiceImpl implements BlogService {
@Inject
private BlogDao blogDao;
public BlogInfo getBlog(int id) {
return blogDao.getBlog(id);
}
}
然后在测试类里调用:
@Test
public void test() {
System.out.println(blogService.getBlog(5));
}
得到了空指针的错误:java.lang.NullPointerException
也就是说BlogServiceImpl的BlogDao 接口为空。
这个是什么原因造成的呢?  回复  更多评论
  

# re: Google Guice 入门教程07 - 整合第三方组件(1) 2011-01-26 10:18 xylz
@lxy

之所以BlogDao为空是因为BlogServiceImpl是由Spring Container托管的,而Spring不支持Guice的Inject注入,因此对于Spring Bean来说,目前还不支持Inject注入Guice 的Bean。

话说回来,你的BlogServiceImpl不也是Spring托管的么?既然这样,你将BlogServiceImpl中的@Inject private BlogDao blogDao;换成@Autowired private BlogDao blogDao;就可以解决此问题了。  回复  更多评论
  

# re: Google Guice 入门教程07 - 整合第三方组件(1) 2011-01-27 09:51 lxy
我是新手,有点明白了。

不是Guice管理的对象,不能由Guice完成注入,应该是这样理解吧?

你的教程很好啊,比Guice的文档要好多了,继续关注。

以后会出guice和mybatis的整合教程么?官方就得一个英文文档,百度也没有详细资料,我虽然已经整合了,但是有些地方不懂。  回复  更多评论
  

# re: Google Guice 入门教程07 - 整合第三方组件(1) 2011-01-27 11:59 xylz
@lxy
理解正确!

guice这东西自己玩玩可以,目前使用的公司还是比较少。至于与ibatis的整合目前没有计划,guice版本更新我倒是可以关注下。  回复  更多评论
  

# re: Google Guice 入门教程07 - 整合第三方组件(1) 2014-04-13 14:32 色的法士大夫
ASAS  回复  更多评论
  


只有注册用户登录后才能发表评论。


网站导航:
 

©2009-2014 IMXYLZ