ALL is Well!

敏捷是一条很长的路,摸索着前进着

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  30 随笔 :: 23 文章 :: 71 评论 :: 0 Trackbacks

本文为原创,欢迎转载,转载请注明出处BlogJava

在上一篇 Hessian构建分布式系统应用 的基础上,我们对程序进行改进。
现在有以下比较突出的问题:
a.如果hessian服务端我要做的业务很多,怎么办?
我要定义很多个接口,然后再写实现类,最烦的是还要配置它。
我的设想是,hessian服务只提供一个归口,再此对外的接口实现中反射调用具体的业务类。

b.客户端在调用时,每次调用远程接口都要用以下代码吗:

String url = "http://localhost:8080/HessianService/remote/service";
HessianProxyFactory factory 
= new HessianProxyFactory();
ServiceRemote rmt 
= (ServiceRemote) factory.create(ServiceRemote.class, url);


显然是不需要的。
我们可以通过加入缓存的方式对其进行改良,我们也可以通过Spring在客户端管理它。

一、完善hessian服务端实现:
1.首先修改ServiceRemote接口:

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,此类不做具体业务,而是反射调用具体业务类:

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

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

<?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="serviceUrl" value="http://localhost:8080/HessianService/remote/service" />
        
<property name="serviceInterface" value="com.al.ServiceRemote" />
    
</bean>
</beans>

 

2.客户端如下调用即可:

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) 等等..
这些在具体的项目中都是不得不考虑的问题。以后再慢慢讨论吧。

posted on 2010-10-17 22:10 李 明 阅读(1696) 评论(1)  编辑  收藏 所属分类: J2EESpring

评论

# re: Hessian构建分布式系统应用[续][未登录] 2012-08-11 15:07 哈哈
目前我正考虑类似的方式构建一个系统出现了一下问题:
1.如你所说,如果只采用一个暴露接口,当访问量比较大时是不是有性能问题呢?
2.服务端的业务异常信息如何返回给客户端?比如,当Insert一条数据,ID重复,目前我是返回一个错误码给客户端,客户端根据错误码得到相应信息


希望多多交流  回复  更多评论
  


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


网站导航: