JAVA—咖啡館

          ——歡迎訪問rogerfan的博客,常來《JAVA——咖啡館》坐坐,喝杯濃香的咖啡,彼此探討一下JAVA技術(shù),交流工作經(jīng)驗,分享JAVA帶來的快樂!本網(wǎng)站部分轉(zhuǎn)載文章,如果有版權(quán)問題請與我聯(lián)系。

          BlogJava 首頁 新隨筆 聯(lián)系 聚合 管理
            447 Posts :: 145 Stories :: 368 Comments :: 0 Trackbacks

          公告

           

          Locations of visitors to this page
          點擊這里給我發(fā)消息 點擊這里給我發(fā)消息

          常用鏈接

          留言簿(17)

          隨筆分類(542)

          隨筆檔案(438)

          文章分類(182)

          文章檔案(142)

          新聞分類

          ※→ 【JAVA文檔】

          ※→ 【親人博客】

          ※→ 【休閑娛樂】

          ※→ 【友情鏈接】

          ※→ 【學(xué)習(xí)網(wǎng)站】

          ※→ 【服務(wù)網(wǎng)站】

          ※→ 【著名網(wǎng)站】

          ※→ 【阿里博客】

          最新隨筆

          搜索

          積分與排名

          最新評論

          閱讀排行榜

          評論排行榜

          遠(yuǎn)程服務(wù)調(diào)用框架設(shè)計與實現(xiàn)

          目的

          為遠(yuǎn)程服務(wù)調(diào)用提供統(tǒng)一的框架,該框架集中解決遠(yuǎn)程調(diào)用過程中的三方面問題:

          a.         應(yīng)用透明性:應(yīng)用的接口和實現(xiàn)不依賴于框架的實現(xiàn)??蚣芸梢酝该鞯那袚Q各種遠(yuǎn)程調(diào)用技術(shù),而上層應(yīng)用的接口和實現(xiàn)不用做任何調(diào)整。
          b.         安全性:安全性主要包括兩個方面:身份及簽名驗證(防篡改偽造);數(shù)據(jù)傳輸保密性(防監(jiān)聽);IP認(rèn)證。
          c.         調(diào)用頻度控制:為保證服務(wù)可用,需要對于調(diào)用頻度根據(jù)一定的規(guī)則進(jìn)行控制。

          實現(xiàn)技術(shù)

            由于調(diào)用雙方都是基于Java的應(yīng)用,實現(xiàn)技術(shù)上建議采用基于Spring的Remoting框架,這樣可以實現(xiàn)應(yīng)用透明性,接口開發(fā)人員不用考慮遠(yuǎn)程調(diào)用等與業(yè)務(wù)無關(guān)的技術(shù)細(xì)節(jié)。基于Spring框架并進(jìn)行擴(kuò)展,我們可以在框架層次實現(xiàn)安全性和調(diào)用頻度限制。

                 由于調(diào)用雙方不在一個局域網(wǎng)環(huán)境內(nèi),因此在具體通訊協(xié)議上,最佳選擇即為Http。因此我們推薦的實現(xiàn)技術(shù)包括:Spring Remoting + Spring HttpInvoker,以及Spring Remoting + Hessian。

                 安全性包括身份驗證和數(shù)據(jù)傳輸安全兩個方面,身份驗證可以根據(jù)調(diào)用雙方的信任程度以及性能要求確定采用對稱加密或者非對稱加密,當(dāng)前提供了三種驗證措施,用戶名加密認(rèn)證,IP認(rèn)證,以及消息數(shù)字摘要加密驗證,該驗證可以在Spring Remoting基礎(chǔ)上進(jìn)行擴(kuò)展。數(shù)據(jù)傳輸安全則主要是擔(dān)心數(shù)據(jù)在傳輸過程中被截獲,對于基于Http的傳輸,使用Https即可(無需在框架或者應(yīng)用層支持)。

                 調(diào)用頻度控制,則可以應(yīng)用AOP技術(shù),對于調(diào)用進(jìn)行截獲和統(tǒng)計,根據(jù)一定的規(guī)則,判斷調(diào)用是否符合控制策略。

          接口定義和實現(xiàn)規(guī)范

            接口定義和實現(xiàn)為簡單的POJI和POJO即可,不過為了滿足遠(yuǎn)程調(diào)用的需要,需要保證所有參數(shù)和返回值都是可序列化的,另外,鑒于部分遠(yuǎn)程調(diào)用技術(shù)的序列化機制的特殊性(例如Hessian),數(shù)據(jù)類型應(yīng)盡可能簡單。此外,基于性能考慮,遠(yuǎn)程接口調(diào)用方式適用于中低頻度的小數(shù)據(jù)量的調(diào)用,對于大批量數(shù)據(jù)同步或者相當(dāng)高頻度的調(diào)用,遠(yuǎn)程接口調(diào)用方式并不合適。

          設(shè)計實現(xiàn)

          基本類圖


           圖1 遠(yuǎn)程服務(wù)發(fā)布類結(jié)構(gòu)圖

                 針對Hessian和HttpInvoker兩種遠(yuǎn)程服務(wù)調(diào)用的方式封裝了對于安全控制的兩個安全發(fā)布類,具體的安全配置以及安全操作都在RemoteContractTemplate中,這樣可以方便擴(kuò)展任何安全的需求變更,并且對原有任何的Exporter做了安全切面處理,防止過度耦合。


          圖 2 遠(yuǎn)程服務(wù)調(diào)用類結(jié)構(gòu)圖

                 遠(yuǎn)程服務(wù)調(diào)用對于不同的方法調(diào)用需要不同的定制,這里針對Hessian和HttpInvoker采用了替換植入內(nèi)部處理類的方式,Hessian植入了新的HessianProxyFactory用來生成新的HessianProxy來植入安全機制,HttpInvokerFactoryBean植入了新的HttpInvokerRequestExecutor來植入安全機制,同樣安全配置以及操作都封裝在RemoteContractTemplate中,集中控制和配置,方便擴(kuò)展和管理。

          基本流程圖

           
          圖 3 基本流程圖

                 如上圖所示,用戶發(fā)起請求調(diào)用遠(yuǎn)程服務(wù),首先是創(chuàng)建遠(yuǎn)程服務(wù)代理,然后通過植入安全信息將請求發(fā)送到遠(yuǎn)程服務(wù)發(fā)布處理類中,首先檢查安全信息,如果通過安全檢測就進(jìn)入方法調(diào)用攔截器中檢驗類似于頻率之類的限制過程中,通過攔截器的檢測就可以調(diào)用真正的遠(yuǎn)程服務(wù),并且獲得結(jié)果,將結(jié)果返回并封裝安全信息返回給服務(wù)調(diào)用代理,代理首先檢測是否有合法的安全信息,如果通過安全信息認(rèn)證,將結(jié)果返回給客戶端。

          具體的配置和使用

            這里通過一個Demo來說明如何使用這個遠(yuǎn)程服務(wù)調(diào)用框架。

            假定一個售票管理服務(wù)要發(fā)布,售票管理服務(wù)結(jié)構(gòu)圖如下:


          圖 4 售票管理服務(wù)結(jié)構(gòu)圖

          服務(wù)類接口為TicketManage,實現(xiàn)類是TicketManageImpl。測試調(diào)用類為TicketManageClient。接口和接口的實現(xiàn)類就是按照普通的Java規(guī)范來實現(xiàn)即可,TicketManageClient根據(jù)你選擇不同的服務(wù)調(diào)用方式來編寫代碼,這里用到了Hessian和HttpInvoker兩種方式,代碼如下:

          public static void  main(String[] args)

              {

                  ApplicationContext ctx = new ClassPathXmlApplicationContext("ticket.xml");

                  TicketManage ticketManage = (TicketManage)ctx.getBean("ticketService");//hession調(diào)用的配置

                  Ticket ticket = ticketManage.buyTicket(20);

                  System.out.println("ticket seat: " + ticket.getSeat());

                 

                  int returncost = ticketManage.returnTicket(ticket);

                  System.out.println("return ticket, get back cost :" + returncost);

                  TicketManage httpTicketManage = (TicketManage)ctx.getBean("ticketHttpService");//HttpInvoke調(diào)用的配置

                  ticket = httpTicketManage.buyTicket(30);

                  System.out.println("ticket seat: " + ticket.getSeat());

                 

                  returncost = httpTicketManage.returnTicket(ticket);

                  System.out.println("return ticket, get back cost :" + returncost);

              }

          ticket.xml是客戶端的spring配置文件,具體的內(nèi)容如下:

          <?xml version="1.0" encoding="GB2312"?>

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

          <beans default-autowire="byName">

              <!—- 安全模版配置類,參數(shù)在后面會有詳細(xì)解釋 -->

              <bean id="remoteContractTemplate" class="com.alibaba.common.remoting.util.RemoteContractTemplate" init-method="init">

                 <property name="encryptKeyPath" value="file:c:\key.ky" />

                 <property name="decryptKeyPath" value="file:c:\key.ky" />

                 <property name="algonrithm" value="RSA"/>

                 <property name="needMD" value="true"/>

                 <property name="needUserAuth" value="true"/>

                 <property name="user">

                     <list>

                     <value>taobao</value>

                     <value>zhifubao</value>

                     <value>b2b</value>

                     </list>

                 </property>

                 <property name="owner" value="alisoft"/>

          <property name="connectTimeout" value="6"/>

          <property name="readTimeout" value="0"/>

                 <property name="needIPAuth" value="true"/>

          <property name="ipList">

                     <list>

                     <value>10.0.26.23</value>

                     <value>10.0.0.42</value>

                     </list>

                 </property>

              </bean>

              <!—- 需要植入到HttpInvokerProxyFactoryBean的安全請求處理類 -->

              <bean id="securityHttpInvokerRequestExecutor" class="com.alibaba.common.remoting.http.SecurityHttpInvokerRequestExecutor">

                 <property name="remoteContractTemplate" ref="remoteContractTemplate" />

              </bean>

              <!—- 發(fā)布服務(wù)的Bean -->

              <bean id="ticketHttpService" class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">

                 <property name="serviceUrl" value="http://localhost:80/remote-examples/remote/TicketHttpService"/>

                 <property name="serviceInterface" value="com.alibaba.common.remoting.test.TicketManage"/>

                 <property name="httpInvokerRequestExecutor" ref="securityHttpInvokerRequestExecutor"/>

              </bean>   

             

          <!—- Hessian的安全代理工廠類Bean -->

              <bean id="securityHessianProxyFactory" class="com.alibaba.common.remoting.hessian.SecurityHessianProxyFactory">

                 <property name="remoteContractTemplate" ref="remoteContractTemplate" />

              </bean>

             

              <bean id="ticketService" class="org.springframework.remoting.caucho.HessianProxyFactoryBean">

                 <property name="serviceUrl" value="http://localhost:80/remote-examples/remote/TicketService"/>

                 <property name="serviceInterface" value="com.alibaba.common.remoting.test.TicketManage"/>

                 <property name="proxyFactory" ref="securityHessianProxyFactory"/>

              </bean>

             

          </beans>

           上面的xml中藍(lán)色的內(nèi)容需要根據(jù)具體的情況作修改,黑色的內(nèi)容則不需要修改。

          安全模版配置類參數(shù)具體說明:下面是代碼中的說明,大家一看就應(yīng)該明白了

          private String encryptKeyPath;//encryptKey的路徑

              private String decryptKeyPath;//decryptKey的路徑

              private Key encryptKey;//根據(jù)encryptKey的路徑生成的key

              private Key decryptKey;//根據(jù)decryptKey的路徑生成的key

              private String algonrithm;//算法

              private String needMD;//是否需要MD校驗

              private String needUserAuth;//是否需要加密

              private List<String> user;//允許對方訪問或者返回結(jié)果的用戶名

              private String owner;//自己的簽名

              private byte[] encrypted;//加密后的用戶簽名,一次加密,多次使用,增加性能提升

              private String encoding = "GB2312";//編碼方式,加密和md的內(nèi)容的編碼方式

              private String needIPAuth;//是否需要IP認(rèn)證

              private List<String> ipList;//允許訪問的ip列表

          private int readTimeout = 0;// 讀取數(shù)據(jù)超時時間設(shè)置,單位秒

              private int connectTimeout = 0;// 連接超時時間設(shè)置,單位秒

          客戶端設(shè)置好以后,就需要設(shè)置服務(wù)端了:

          服務(wù)端很簡單首先是類似于Spring的Hessian和HttpInvoker調(diào)用的配置一樣,在WEB-INF/lib下面放入toolkit-sandbox-remoting.jar以及其它以來的jar,然后配置web.xml,增加如下內(nèi)容(這都是spring mvc框架的配置,大家可以參考spring來配置):

          <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>

           

          然后在WEB-INF下面新建remote-servlet.xml,如果要換名稱,需要在上面的配置文件配置。

          remote-servlet.xml內(nèi)容如下:

          <?xml version="1.0" encoding="UTF-8"?>

          <beans xmlns="http://www.springframework.org/schema/beans"

            xmlns:sca="http://www.springframework.org/schema/sca"

            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

            xmlns:osgi="http://www.springframework.org/schema/osgi"

            xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/sca http://www.springframework.org/schema/sca/spring-sca.xsd http://www.springframework.org/schema/osgi http://www.springframework.org/schema/osgi/spring-osgi.xsd" default-autowire="byName">

              <bean id="ticketManageTarget" class="com.alibaba.common.remoting.test.TicketManageImpl" />

             

              <bean id="ticketManage" class="org.springframework.aop.framework.ProxyFactoryBean">

                 <property name="proxyInterfaces" value="com.alibaba.common.remoting.test.TicketManage" />

                 <property name="target"><ref local="ticketManageTarget" /></property>

                 <!—-  攔截器bean  -->

                 <property name="interceptorNames">

                   <list>

                     <value>remoteMethodInterceptor</value>

                   </list>

                 </property>

              </bean>

             

              <bean id="remoteMethodInterceptor" class="com.alibaba.common.remoting.interceptor.RemoteCounterInterceptor" >

                 <property name="valve" value="20"/><!—-  閥值代表次數(shù)  -->

                 <property name="policy" value="hour"/><!—- 策略,當(dāng)前提供hour,day,month三種  -->

                 <!—-  上面的配置代表了每小時不能超過20次的訪問  -->

              </bean>

             

              <bean id="remoteContractTemplate" class="com.alibaba.common.remoting.util.RemoteContractTemplate" init-method="init">

                 <property name="encryptKeyPath" value="file:c:\key.ky" />

                 <property name="decryptKeyPath" value="file:c:\key.ky" />

                 <property name="algonrithm" value="RSA"/>

                 <property name="needMD" value="true"/>

                 <property name="needUserAuth" value="true"/>

                 <property name="user">

                     <list>

                     <value>alisoft</value>

                     <value>zhifubao</value>

                     <value>b2b</value>

                     </list>

                 </property>

                 <property name="owner" value="taobao"/>

          <property name="connectTimeout" value="6"/>

          <property name="readTimeout" value="0"/>

              </bean>

              <!—-  HttpService發(fā)布Bean,植入了安全策略配置模版  -->

              <bean name="/TicketHttpService" class="com.alibaba.common.remoting.http.SecurityHttpInvokerServiceExporter">

                 <property name="service" ref="ticketManage"/>

                 <property name="serviceInterface" value="com.alibaba.common.remoting.test.TicketManage"/>

                 <property name="remoteContractTemplate" ref="remoteContractTemplate" />

              </bean>

             

          <!—-  Hessian服務(wù)發(fā)布Bean,植入了安全策略配置模版  -->

              <bean name="/TicketService" class="org.springframework.remoting.caucho.SecurityHessianServiceExporter">

                 <property name="service" ref="ticketManage"/>

                 <property name="serviceInterface" value="com.alibaba.common.remoting.test.TicketManage"/>

                 <property name="remoteContractTemplate" ref="remoteContractTemplate" />

              </bean>   

             

          </beans>

          最后需要做的就是生成key,當(dāng)前key的算法有兩種,對稱加密和非對稱加密,分別用AES算法和RSA算法,注意一旦產(chǎn)生了Key文件,雙方就要使用相同的key文件,同一個用戶加解密的key文件可以不一致,但是雙方的解密和加密文件必須配對使用。

          產(chǎn)生key文件的方法如下:

          將toolkit-sandbox-remoting.jar所在的位置配置到classpath中,然后通過命令行執(zhí)行。

          生成對稱加密key文件命令為:

          Java com.alibaba.common.remoting.cryption.KeyGenTool genkey 文件目錄 文件名

          生成非對稱加密key文件命令為:

          Java com.alibaba.common.remoting.cryption.KeyGenTool genkeypair 文件目錄 文件名

          這樣你分別會在文件目錄中找到對應(yīng)得文件,后綴名為.ky

           評論 查看全部評論
           
          lithor 于 2008-03-02
          遠(yuǎn)程調(diào)用過程中的三個問題,在SOA服務(wù)調(diào)用過程中也應(yīng)該首先得到解決。不知道SOA服務(wù)調(diào)用相對于文中遠(yuǎn)程過程調(diào)用有哪些相同點和不同點?
           
          l.zw 于 2007-12-22
          這種遠(yuǎn)程調(diào)用,和我們熟知的遠(yuǎn)程查看并協(xié)助,有什么相同之處嗎?
           
          sduboy 于 2007-12-22
          To l.zw:岑兄所說的遠(yuǎn)程服務(wù)調(diào)用和你所說的遠(yuǎn)程查看并協(xié)助根本就不是一碼事吧?無可比性啊。
           
          l.zw 于 2007-12-22
          真是辛苦??!我們周末還給大賽添磚加瓦。
           
          l.zw 于 2007-12-10
          基于Spring框架進(jìn)行擴(kuò)展,遠(yuǎn)程服務(wù)調(diào)用提供這一框架可以在框架層次實現(xiàn)安全性,這可以有效解決當(dāng)前普遍存在的安全問題。
           
          sduboy 于 2007-12-10
          對于遠(yuǎn)程服務(wù)調(diào)用來說,Spring技術(shù)可以說是最好的選擇了吧。

           

          posted on 2008-07-11 17:55 rogerfan 閱讀(2072) 評論(0)  編輯  收藏 所屬分類: 【Java知識】
          主站蜘蛛池模板: 株洲县| 万全县| 大姚县| 上杭县| 清水河县| 南陵县| 临西县| 白水县| 图们市| 子洲县| 宿松县| 青岛市| 石渠县| 古交市| 衡山县| 贵州省| 连山| 英超| 郓城县| 汨罗市| 青川县| 思南县| 永川市| 茂名市| 郧西县| 克山县| 时尚| 革吉县| 博爱县| 鄂托克旗| 江北区| 扬州市| 兴海县| 灵璧县| 台江县| 伊吾县| 武强县| 荥阳市| 登封市| 南郑县| 朔州市|