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 李 明 閱讀(1704) 評論(1)  編輯  收藏 所屬分類: J2EE 、Spring

          評論

          # re: Hessian構建分布式系統應用[續][未登錄] 2012-08-11 15:07 哈哈
          目前我正考慮類似的方式構建一個系統出現了一下問題:
          1.如你所說,如果只采用一個暴露接口,當訪問量比較大時是不是有性能問題呢?
          2.服務端的業務異常信息如何返回給客戶端?比如,當Insert一條數據,ID重復,目前我是返回一個錯誤碼給客戶端,客戶端根據錯誤碼得到相應信息


          希望多多交流  回復  更多評論
            


          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 杨浦区| 横山县| 怀远县| 达拉特旗| 武邑县| 伊川县| 昭觉县| 桃源县| 仁怀市| 东兰县| 三门峡市| 瑞安市| 东乌珠穆沁旗| 醴陵市| 扎赉特旗| 遵义市| 进贤县| 营口市| 富源县| 徐汇区| 陆丰市| 克什克腾旗| 九寨沟县| 依安县| 莱阳市| 新和县| 读书| 淳安县| 永安市| 永新县| 南召县| 周宁县| 城口县| 沅江市| 禹州市| 和林格尔县| 巴林左旗| 台东市| 垫江县| 遂川县| 青龙|