zoukankan      html  css  js  c++  java
  • [转载]Hessian构建分布式系统应用 2

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

  • 相关阅读:
    js 基于函数伪造的方式实现继承
    js 创建List<Map> 这种格式的集合
    微信get post请求到微信服务器 模版 素材操作
    微信开发学习 问题1: 网页授权问题 “该连接无法访问” 解决方法
    Jackson 高性能的JSON处理 ObjectMapper
    baseDao 使用spring3+hibernate4方式
    PropertiesUtil 读取配置文件工具类
    C语言(函数)学习之strstr strcasestr
    命令行选项解析函数(C语言):getopt()和getopt_long()
    AE插件开发的一些总结
  • 原文地址:https://www.cnblogs.com/licomeback/p/3522810.html
Copyright © 2011-2022 走看看