现在有以下比较突出的问题:
a.如果hessian服务端我要做的业务很多,怎么办?
我要定义很多个接口,然后再写实现类,最烦的是还要配置它。
我的设想是,hessian服务只提供一个归口,再此对外的接口实现中反射调用具体的业务类。
b.客户端在调用时,每次调用远程接口都要用以下代码吗:
1
2
3 |
HessianProxyFactory factory = new
HessianProxyFactory(); ServiceRemote rmt = (ServiceRemote) factory.create(ServiceRemote. class , url); |
显然是不需要的。
我们可以通过加入缓存的方式对其进行改良,我们也可以通过Spring在客户端管理它。
一、完善hessian服务端实现:
1.首先修改ServiceRemote接口:
1
2
3
4
5
6
7
8 |
package
com.al; import
java.util.Map; @SuppressWarnings ( "unchecked" ) public
interface
ServiceRemote { public
Map callService(String target, Map inputMap) throws
Exception; } |
callService为统一入口,在此做如下约定:
1)target字符串为要调用的service的完整类路径+要调用的方法。
2)service的方法均用以下方法签名:
public
Map ***(Map
inputMap);
入参为Map,返回值也为Map,基本可以满足所有情况了。(至少入参为Map,很适合调用iBatis来对DB进行操作。)
2.修改接口实现类Service,此类不做具体业务,而是反射调用具体业务类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 |
package
com.al; import
java.lang.reflect.Method; import
java.util.Map; import
org.apache.commons.beanutils.MethodUtils; import
org.apache.commons.lang.StringUtils; @SuppressWarnings ( "unchecked" ) public
class
Service implements
ServiceRemote { public
Map callService(String target, Map inputMap) throws
Exception { String className = StringUtils.substringBeforeLast(target, "." ); String methodName = StringUtils.substringAfterLast(target, "." ); Class serviceClass = loadClass(className); Method method = getMethod(serviceClass, methodName, Map. class ); // 提供访问效率 method.setAccessible( true ); // 调用具体业务类 return
(Map) method.invoke(serviceClass.newInstance(), inputMap); } private
static
<T> Class<T> loadClass(String className) throws
ClassNotFoundException { return
(Class<T>) getClassLoader().loadClass(className); } private
static
ClassLoader getClassLoader() { return
Thread.currentThread().getContextClassLoader(); } private
static
Method getMethod(Class<?> cls, String name, Class<?> parameterTypes) { return
MethodUtils.getAccessibleMethod(cls, name, parameterTypes); } } |
3.举个例子,服务端提供业务类DisplayUserService.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 |
package
com.al.service; import
java.util.HashMap; import
java.util.Map; @SuppressWarnings ( "unchecked" ) public
class
DisplayUserService { public
static
final
String selectUsers = "com.al.service.DisplayUserService.selectUsers" ; public
static
final
String deleteUser = "com.al.service.DisplayUserService.deleteUser" ; public
Map selectUsers(Map inputMap) { Map ret = new
HashMap(); // 数据库操作取得用户列表 省略 ret.put( "User" , "User" ); return
ret; } public
Map deleteUser(Map inputMap) { // 数据库操作取得用户列表 省略 return
null ; } } |
所有其他配置不变,请参考上一篇 Hessian构建分布式系统应用 。
二、客户端代码的修改:
1.加入spring进行管理:
application.xml
1
2
3
4
5
6
7
8 |
<?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= "serviceRemote"
class = "org.springframework.remoting.caucho.HessianProxyFactoryBean" > <property name= "serviceInterface"
value= "com.al.ServiceRemote"
/> </bean> </beans> |
2.客户端如下调用即可:
1
2
3
4
5
6
7
8
9
10
11
12
13
14 |
package
com.ai.client; import
org.springframework.context.support.ClassPathXmlApplicationContext; import
com.al.ServiceRemote; import
com.al.service.DisplayUserService; public
class
ClientTest { public
static
void
main(String[] args) throws
Exception { ClassPathXmlApplicationContext cxt = new
ClassPathXmlApplicationContext( "application.xml" ); ServiceRemote rmt = (ServiceRemote)cxt.getBean( "serviceRemote" ); System.out.println(rmt.callService(DisplayUserService.selectUsers, null )); } } |
另外一种方法是自己实现缓存。
也就是第一次调用远程代码时生成ServiceRemote对象,将其保存在静态的容器(HashMap)中,
每次准备调用此远程代码时,先判断容器中是否有ServiceRemote对象,有则直接将其取出并使用即可,要注意的就是在这个容器上的同步问题。
具体实现就不做了,很简单。
在项目中,对于客户端代码来讲,还是有许多工作要做的:
1)
如果我们要调用多个远程服务怎么办?
我们要提供一个统一调用,将远程调用的动作封装起来,让使用的人不知道自己调用了不同的远程服务。
只要调用某个方法、传入参数即可。
2)
如何方便开发员调试远程的服务代码?
在做分布式系统开发的时候,如果每修改一下应用层的service,就要对其进行发布,然后再去调用看是否已OK,那效率会很低。
3) 如何管理多方调用的远程服务?
4)
如何提高远程调用的效率?
是否可以通过对 对象进行缓存、方法是否也可以缓存?甚至是对调用结果进行缓存?
5)
等等..
这些在具体的项目中都是不得不考虑的问题。以后再慢慢讨论吧。
原文:http://www.cnblogs.com/licomeback/p/3522810.html