论坛首页 Java版 Spring

用spirng和hessian构建分布式应用(远程接口)的方法[原]

浏览 8892 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
时间:2005-07-27
最近一期的《programmer》里几乎从头至尾在讲关于“J2EE without EJB”的事情,可怜的ejb啊,居然被描述成了遗产系统的重要组成部分。。。

其实有上面的结论,无外乎现在java里面的新技术已经几乎能完全取代ejb的优点,而克服ejb的缺点,entity bean和有状态的session bean已经机乎被视为垃圾,hibernate和spring大行其到,看看最进n期《programmer》中篇幅的比重就知道了。本来我个人的感觉是hibernate取代了entity bean,spring取代了session bean,但是ejb的远程调用用hibernate和spring的架构还取代不了,可是在最近的一期《programmer》中我发现了Hessian!更爽的是,发现了spring原来可以和Hessian结合使用!看来真的可以say byebye to ejb了。

看到这么振奋人心的消息,怎么能不亲自试验一下呢,于是上http://www.caucho.com/以迅雷不及掩耳盗铃之势下载了Hessian的src jar和bin jar。create一个工程,把这些相关的jar统统扔进去,配置和coding就可以开始了。首先,开了如下几个包:



whao.test.hessian.server
放远程服务的接口

whao.test.hessian.server.impl
放远程服务的实现类

whao.test.hessian.client
放客户端应用



1. whao.test.hessian.server中写一个MyService接口:
[code:1]
/*

* Created on 2005-7-25

*

*/

package whao.test.hessian.server;



/**

* @author Hao Wei

*

*/

public interface MyService {

public String doSomething(String s);

}
[/code:1]


2. whao.test.hessian.server.impl中写一个实现类

[code:1]
/*

* Created on 2005-7-25

*

*/

package whao.test.hessian.server.impl;



import whao.test.hessian.server.MyService;



/**

* @author Hao Wei

*

*/

public class MyServiceImpl implements MyService {



/* (non-Javadoc)

* @see whao.test.hessian.server.MyService#doSomething(java.lang.String)

*/

public String doSomething(String s) {

return "HAHAHA: " + s;

}

}

[/code:1]

3. 配置远程服务

Hessian的远程服务要配置成servlet,配置如下:
[code:1]

<servlet>

<servlet-name>myservice</servlet-name>

<servlet-class>com.caucho.hessian.server.HessianServlet</servlet-class>

<load-on-startup>1</load-on-startup>

<init-param>

<param-name>service-class</param-name>

<param-value>whao.test.hessian.server.impl.MyServiceImpl</param-value>

</init-param>

</servlet>

<servlet-mapping>

<servlet-name>myservice</servlet-name>

<url-pattern>/myservice</url-pattern>

</servlet-mapping>

[/code:1]

这样,当启动了这个web应用,这个远程服务就以url http://localhost:8080/test_web/myservice 的形式发布了。然后就是开发客户端来调用这个远程服务。

[code:1]
/*

* Created on 2005-7-25

*

*/

package whao.test.hessian.client;



import whao.test.hessian.server.MyService;



import com.caucho.hessian.client.HessianProxyFactory;



/**

* @author Hao Wei

*

*/

public class TestMain {

public static void main(String[] args) throws Exception {

HessianProxyFactory proxyFactory = new HessianProxyFactory();

MyService service = (MyService) proxyFactory.create(MyService.class,

"http://localhost:8080/test_web/myservice");

System.out.println(service.doSomething("xixixixi"));

System.out.println("ok!");

}

}

[/code:1]

运行一把,显示

HAHAHA:xixixi

ok!

不错不错,纯Hessian的远程调用就这样搞定了。继续研究《programmer》看到上面介绍用spring的远程访问解决方案来访问ejb的远程服务。什么?spring还有远程解决方案?没听说过嘛,看了《programmer》上的介绍,发现是真的。那么既然spring能访问ejb的远程服务,那么能访问Hessian的远程服务么?打开spring.jar看看,居然发现了名曰org.springframework.remoting.caucho.HessianProxyFactoryBean的类!夏昕真不厚道啊,再他的spring中文教程中居然匿掉了spring里这么好的东西!于是打开sping英文版reference,终于找到了用spring配置Hessian客户端的方法:
[code:1]
<bean id="myService" class="org.springframework.remoting.caucho.HessianProxyFactoryBean">

<property name="serviceUrl">

<value>

http://localhost:8080/test_web/myservice

</value>

</property>

<property name="serviceInterface">

<value>whao.test.hessian.server.MyService</value>

</property>

</bean>

[/code:1]
然后客户端就可以这么玩啦:

[code:1]
/*

* Created on 2005-7-25

*

*/

package whao.test.hessian.client;



import whao.test.hessian.server.MyService;

import whao.util.spirng.SpringBeanFactory;



import com.caucho.hessian.client.HessianProxyFactory;



/**

* @author Hao Wei

*

*/

public class TestMain {



public static void main(String[] args) throws Exception {

testWithSpring();

}

public static void testWithSpring(){

MyService service = (MyService)SpringBeanFactory.getBean("myService");

System.out.println(service.doSomething("lllllllll"));

System.out.println("ok!");

}

public static void testWithoutSpring() throws Exception {

HessianProxyFactory proxyFactory = new HessianProxyFactory();

MyService service = (MyService) proxyFactory.create(MyService.class,

"http://localhost:8080/test_web/myservice");

System.out.println(service.doSomething("xixixixi"));

System.out.println("ok!");

}

}

[/code:1]

执行一下,输出是:

HAHAHA:lllllllll

ok!

spring真是个好东东,呵呵,其中的SpringBeanFactory是这样实现的:
[code:1]

/*

* Created on 2005-7-25

*

*/

package whao.util.spirng;



import javax.servlet.ServletContext;



import org.apache.commons.logging.Log;

import org.apache.commons.logging.LogFactory;

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.FileSystemXmlApplicationContext;

import org.springframework.web.context.support.WebApplicationContextUtils;



/**

* @author Hao Wei

*

*/

public class SpringBeanFactory {

private static final Log log = LogFactory.getLog(SpringBeanFactory.class);

private static ApplicationContext ctx = null;



public static Object getBean(ServletContext context, String beanID) {

log.info("beanID=" + beanID);

ApplicationContext ac = WebApplicationContextUtils

.getWebApplicationContext(context);

return ac.getBean(beanID);

}



public static Object getBean(String beanID){

if(ctx == null){

ctx = new FileSystemXmlApplicationContext(

"D:\\whao-work\\src\\test_web\\test_web\\WEB-INF\\applicationContext.xml");

}

return ctx.getBean(beanID);

}

}

[/code:1]

看到sping.jar的包org.springframework.remoting.caucho中还有另外两个类叫HessianClientInterceptor和HessianServiceExporter,看来貌似hessian服务端也可以和spring结合,还有客户端的Interceptor估计可以实现对远程服务的AOP,要继续研究一下了,待续吧
   
时间:2005-07-31
在成功的将hessian server端也和spring结合后,从整个分布式应用的架构可以看出,无论是服务端与客户端共有的业务接口,还是服务端业务实现类,以及客户端访问远程服务的应用代码里,已经没有一行关于远程操作的代码了。也就是spring让我们的分布式业务开发完全无关于远程访问协议了,这样我们就可以埋头开发服务端和客户端的业务接口、实现、应用等等,二不必关心远程调用究竟要怎么实现。很明显,这也是AOP(面向方面的编程)的一个比较完美的应用,它使远程访问接口和业务逻辑完全无耦合的分开了。设想一下,如果某天我们有需要,远程访问的接口要从rmi、jax-rpc、hessian、httpinvoker之间做切换,也只要改下配置文件就ok了,一行代码都不用改,真的非常exciting。

接着前面那篇日志,先把spring和hessian在服务端的结合帖上来:

接口,还是那个接口~;实现,还是那个实现~~;配置却不是了那个配置呀~~~

首先,servlet变成了:
[code:1]
<servlet>

<servlet-name>remote</servlet-name>

<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

<load-on-startup>1</load-on-startup>

</servlet>

<servlet-mapping>

<servlet-name>remote</servlet-name>

<url-pattern>/remote/*</url-pattern>

</servlet-mapping>

[/code:1]
其次,applicationContext.xml没有必要了,但是要有个remote-servlet.xml,内容如下:

[code:1]
<?xml version="1.0" encoding="UTF-8"?>

<!-- edited with XMLSPY v5 rel. 4 U (http://www.xmlspy.com) by whao (mdc) -->

<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">

<beans>

<description>server properties</description>

<bean id="_myService_server" class="whao.test.hessian.server.impl.MyServiceImpl">

</bean>

<bean name="/myService_server" class="org.springframework.remoting.caucho.HessianServiceExporter">

<property name="service">

<ref bean="_myService_server"/>

</property>

<property name="serviceInterface">

<value>whao.test.hessian.server.MyService</value>

</property>

</bean>

</beans>

[/code:1]

这样一来这个hessian服务的发布地址就变成了 http://localhost:8080/test_web/remote/myService_server

客户端的配置改成:
[code:1]
<bean id="myServiceClient" class="org.springframework.remoting.caucho.HessianProxyFactoryBean">

<property name="serviceUrl">

<value>http://localhost:8080/test_web/remote/myService_server</value>

</property>

<property name="serviceInterface">

<value>whao.test.hessian.server.MyService</value>

</property>

</bean>
[/code:1]


客户端的代码依然是:
[code:1]

MyService service = (MyService)SpringBeanFactory.getBean("myServiceClient");

System.out.println(service.doSomething("mmmmmmmmm"));

[/code:1]

运行一下,输出:

HAHAHA: mmmmmmmmm

ok!



嗯,真是不错,下面尝试着不改一行代码,我们把远程协议由hessian改成rmi。

由于rmi server不用servlet,也就不用web server,所以可以由自己的进程之接启动,我们就把remote-servlet.xml改成beans.xml内容如下:

[code:1]
<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">

<beans>

<bean id="_myService_server" class="whao.test.hessian.server.impl.MyServiceImpl">

</bean>

<bean id="myService_server" class="org.springframework.remoting.rmi.RmiServiceExporter">

<property name="serviceName"><value>myService_server</value></property>

<property name="service"><ref bean="_myService_server"/></property>

<property name="serviceInterface"><value>whao.test.hessian.server.MyService</value></property>

</bean>

</beans>

[/code:1]

然后随便写个main程序启动服务,就不用启动web server了:

[code:1]
/*

* Created on 2005-7-31

*

*/

package whao.test.rmi;



import org.springframework.context.ApplicationContext;

import org.springframework.context.support.FileSystemXmlApplicationContext;



/**

* @author Hao Wei

*

*/

public class Server {

public static void main(String[] args) throws Exception{

ApplicationContext ctx = new FileSystemXmlApplicationContext("D:\\whao-work\\src\\test_web\\src_server\\beans.xml");

ctx.getBean("myService_server");

System.out.println("Server started");

}

}
[/code:1]


这样,我们的服务接口和实现类的代码一行不用动,而变成rmi协议的服务已经以rmi://localhost/myService_server 的url启动了。

然后在把客户端的配置略微调整一下:
[code:1]
<bean id="myServiceClient" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">

<property name="serviceUrl">

<value>rmi://localhost/myService_server</value>

</property>

<property name="serviceInterface">

<value>whao.test.hessian.server.MyService</value>

</property>

</bean>


[/code:1]
客户端的代码也一行不动,在执行下,输出依然是:

HAHAHA: mmmmmmmmm

ok!

然而,我们的remoting其实已经由基于http的hessian改成了rmi。果然不错啊,除了hessian,rmi之外,现在spring支持的remoting协议还包括jax-rpc,burlap,httpinvoker,也就是说我们的remoting操作协议在这些中间切换时,利用spring remoting框架,都可以不用改一行代码,已经非常强大了,只是现在还没有corba的支持。
   
0 请登录后投票
时间:2005-07-31
不错

其实远程调用关键是选用什么协议.
spring的文档里说了.比如hession,当domain model用hibernate的延迟加载就不可以了.

象这种轻量级的协议,只能实现简单的分布式应用.
当我们需要分布式事务时当然还要 ejb corbol等重量级的技术.
   
0 请登录后投票
时间:2005-10-27
zkj_beyond 写道
不错

其实远程调用关键是选用什么协议.
spring的文档里说了.比如hession,当domain model用hibernate的延迟加载就不可以了.

象这种轻量级的协议,只能实现简单的分布式应用.
当我们需要分布式事务时当然还要 ejb corbol等重量级的技术.

晕了,难道真的不行么?hibernate不用延迟加载简直是不可能的,难道真的要放弃hession么?
   
0 请登录后投票
时间:2005-10-27
RMI在SPRING中用起来也很方便,不必EJB!
   
0 请登录后投票
时间:2005-10-28
yuqf 写道
zkj_beyond 写道
不错

其实远程调用关键是选用什么协议.
spring的文档里说了.比如hession,当domain model用hibernate的延迟加载就不可以了.

象这种轻量级的协议,只能实现简单的分布式应用.
当我们需要分布式事务时当然还要 ejb corbol等重量级的技术.

晕了,难道真的不行么?hibernate不用延迟加载简直是不可能的,难道真的要放弃hession么?

Remoting调用应当引入DTO进行解耦
   
0 请登录后投票
时间:2005-10-28
spring提供很多种remote方式,我试了一下http invoker,对延迟加载是可以支持的。
   
0 请登录后投票
时间:2005-11-22
如果需要检查client的权限,该怎么做?
client使用的接口和server发布的接口不一样好象也能用,只要方法一样就可以,是这样吗?
如果server用的JAVA那么client能用其他的语言写吗?
   
0 请登录后投票
时间:2005-11-22
yuqf 写道
spring提供很多种remote方式,我试了一下http invoker,对延迟加载是可以支持的。



http invoker 的remote call,延迟加载恐怕行不通吧?下面是我拍脑瓜子的分析:

http是非连续的协议;
一次http invoke,取出order,serialize/deserialize之后,如何再去获取延迟加载的集合属性 order.getDetailItem()?如何配置open session in view?

很想看一下你的代码片断是如何解决这些问题的。



引用
Hessian and/or Burlap might provide significant value when operating in a heterogeneous environment,
because they explicitly allow for non-Java clients. However, non-Java support is still limited. Known problems
include the serialization of Hibernate objects in combination with lazily initializing collections. If you have
such a data model, consider using RMI or HTTP invokers instead of Hessian.


spring的reference中好像给出了这种可能,只是我没想通如何能实现?
   
0 请登录后投票
时间:2006-03-24
发布的hessian接口不能支持重载
   
0 请登录后投票
论坛首页 Java版 Spring

跳转论坛: