月蝕傳說

          浮躁讓人失去理智
          posts - 25, comments - 101, trackbacks - 0, articles - 0
            BlogJava :: 首頁 ::  :: 聯(lián)系 :: 聚合  :: 管理

          1.? 遠(yuǎn)程服務(wù)概念


          顧名思義,遠(yuǎn)程服務(wù)是指可以通過遠(yuǎn)程通訊進(jìn)行調(diào)用的服務(wù)。

          SCA 中,在定義服務(wù)的時(shí)候可以將服務(wù)定義為遠(yuǎn)程服務(wù),通過 @Remotable 標(biāo)簽加在服務(wù)接口的類名上,就將該服務(wù)接口定位為了遠(yuǎn)程服務(wù)。


          SCA
          規(guī)范中這樣規(guī)定遠(yuǎn)程服務(wù)的

          Remotable services are services that can be published through entry points. Published services can be?
          accessed by clients outside of the module that contains the component that provides the service.

          Whether a service is remotable is defined by the interface of the service. In the case of Java this is defined

          by adding the @Remotable annotation to the Java interface. A service whose interface is defined by a Java class is not remotable. "


          上面這段話主要意思是說,一個(gè)遠(yuǎn)程服務(wù)可以通過
          Entry Points 進(jìn)行發(fā)布,并且能夠被該服務(wù)所在模塊以外,但包含了該服務(wù)的組件所調(diào)用,并且,遠(yuǎn)程服務(wù)只能定義在 Java 接口類上,如果利用 Java 實(shí)現(xiàn)類(非 interface java 類)定義的服務(wù)進(jìn)行 @Remotable 注釋,這種遠(yuǎn)程服務(wù)是無效的。


          可能上面的話有點(diǎn)太含糊其詞,我們下面具體講一下
          SCA 遠(yuǎn)程服務(wù)的定義,以及 uxsca 容器實(shí)現(xiàn)該標(biāo)準(zhǔn)的簡(jiǎn)要實(shí)現(xiàn)手段。


          2.?
          定義遠(yuǎn)程服務(wù)

          根據(jù)上面我們所講的,在一個(gè)已經(jīng)被定義為服務(wù)的接口的接口類上加上注釋 @Remotable ,這樣就表示該 sca 服務(wù)將會(huì)是一個(gè)遠(yuǎn)程服務(wù)。就這么簡(jiǎn)單!


          3
          UxSCA 容器中遠(yuǎn)程服務(wù)的實(shí)現(xiàn)概要


          的確,光從
          sca 規(guī)范上來看,一個(gè)遠(yuǎn)程服務(wù)的定義是如此簡(jiǎn)單,但是具體怎么去使用以及使用場(chǎng)合 ,SCA 規(guī)范中沒有給出詳細(xì)的示例,所以這里我也只能是根據(jù)遠(yuǎn)程服務(wù)定義去做實(shí)現(xiàn)了。


          既然是遠(yuǎn)程服務(wù),首先想到的實(shí)現(xiàn)手段就是
          Web service ,當(dāng)然,也可以用 Java 遠(yuǎn)程調(diào)用。


          既然使用
          Web service ,那在 Java 語言里, Axis 是一個(gè)既簡(jiǎn)單又使用的 Web service 組件了。這里簡(jiǎn)單說一下 Axis 是如何實(shí)現(xiàn) web service 的:


          Axis
          其實(shí)也是通過 servlet 來實(shí)現(xiàn) web service 的,通過一個(gè) HTTP 的訪問, Axis servelet 會(huì)去獲得這段 HTTP Request 信息, HTTP 協(xié)議上架著 SOAP , Axis 解析出 SOAP 后定位到具體的一個(gè) Java 實(shí)現(xiàn),然后在將該 Java 實(shí)現(xiàn)執(zhí)行后的結(jié)果(或者沒有返回結(jié)果)再構(gòu)造成對(duì)應(yīng)的 SOAP 返回回去。一般情況下,訪問 Axis 的客戶端是使用的 Axis 生成的客戶端代碼。 Axis web service 實(shí)現(xiàn)大致如上所述,如有錯(cuò)誤請(qǐng)讀者指出。


          Axis
          創(chuàng)建 Web service 的方法一般有 2 種:

          1?. Axis 實(shí)現(xiàn) Web service 可以通過 jws 文件來定位服務(wù),也就是將一個(gè)寫好的單獨(dú)的 Java 類( .java 文件)改后綴名為 .jws ,然后放到 Axis webapp 下。訪問的 URL 如下:


          ??????????????? Http://webserveraddress/axis/services/SomeJws.jws


          當(dāng)我們通過上面的
          url 去訪問的時(shí)候, Axis 會(huì)去查找編譯好的 java 類,然后執(zhí)行后返回結(jié)果。

          這種方法很簡(jiǎn)單,但是很不實(shí)用。

          2.
          Axis 可以通過生成好的 wsdl ,利用 WSDL2Java 工具類產(chǎn)生 Axis 所需要的 wsdd 配置文件,并且生成對(duì)應(yīng)客戶端以及一些數(shù)據(jù)對(duì)象( DO )代碼。然后通過 Axis 工具類生成一個(gè) server-config.wsdd 文件,將原先生成好的 wsdd 文件中的 service 配置加入到其中,再生成編譯好的 Java 類連同 server-config.wsdd 配置文件一同放到 Axis webapp 目錄下對(duì)應(yīng)的位置,這樣可以通過 Axis 生成的客戶端去調(diào)用這個(gè) web service 了。

          ?

          UxSCA 是利用第二種方式去構(gòu)建遠(yuǎn)程服務(wù)的。步驟如下:


          UxSCA
          本身是一個(gè) Web 應(yīng)用,它的 web.xml 中加入了 Axis servlet ,這樣就可以不去單獨(dú)將 Axis 作為一個(gè) Web 應(yīng)用來獲得 Web service 的請(qǐng)求了。而 UxSCA 在啟動(dòng)的時(shí)候(并不是 Web 服務(wù)容器啟動(dòng)的時(shí)候),會(huì)去解析在自己維護(hù)下的模塊,從而獲得各個(gè)模塊的服務(wù)配置,然后:

          1. 首先解析出遠(yuǎn)程服務(wù)接口類,以及其實(shí)現(xiàn)類。

          2.?? 然后邊歷接口類中可以發(fā)布的接口方法(可發(fā)布的接口方法,必須是參數(shù)或者返回值都是簡(jiǎn)單類型或者是 SDO 類型),生成對(duì)應(yīng)的 WSDL 文件。

          3.?? 利用生成好的 WSDL 文件以及服務(wù)接口類再生成 server-config.wsdd 中的 service 元素片段,并加入到該文件中(如果 server-config.wsdd 不存在, UxSCA 會(huì)自動(dòng)生成)

          在作完以上工作后, UxSCA 會(huì)去自動(dòng)啟動(dòng) Web 服務(wù)容器,這樣一來,遠(yuǎn)程調(diào)用就可以通過 uxsca 容器去訪問遠(yuǎn)程服務(wù)了。

          ?

          其中有幾個(gè)問題存在:

          1.??? 服務(wù)的查詢是由 SCA 容器去管理的,外部具有遠(yuǎn)程服務(wù)的接口的模塊組件怎么去獲得非本地模塊中的服務(wù)定義呢?

          2.??
          Axis 目前只支持 Castor XMLBean 或者 JavaBean 的復(fù)雜類型數(shù)據(jù)結(jié)構(gòu),如何讓 Axis 支持 SDO 以及 JAXB 數(shù)據(jù)結(jié)構(gòu)呢?

          3.?? 如果外部模塊獲得了遠(yuǎn)程服務(wù)的接口, SCA 容器在返回接口實(shí)現(xiàn)的時(shí)候卻不會(huì)有一個(gè)真正的接口類實(shí)現(xiàn),就是說,外
          部模塊只有一個(gè)
          interface 類,沒有實(shí)現(xiàn)類(廢話),如何去返回一個(gè)能讓其調(diào)用的類呢?


          對(duì)于第一個(gè)問題,我本人沒有想好,目前也只有一個(gè)不成熟的解決辦法:
          SCA 在部署的時(shí)候能夠知道各個(gè)節(jié)點(diǎn)的位置,然后再統(tǒng)一啟動(dòng),每一個(gè)節(jié)點(diǎn)啟動(dòng)解析完成后再通過網(wǎng)絡(luò)通訊將解析出來的服務(wù)模型反饋給每一個(gè)接點(diǎn),這樣每一個(gè)接點(diǎn)上都會(huì)有其他接點(diǎn)的服務(wù)描述,于是在使用 ModuleContext 定位服務(wù)時(shí)候也就可以作到一致了。當(dāng)然這只是我個(gè)人的想法,行不行得通還需要再去熟悉 SCA 規(guī)范后加上實(shí)踐才能證明其合理性。


          第二個(gè)問題相對(duì)簡(jiǎn)單一點(diǎn),請(qǐng)看我的另一篇文章:
          Axis 支持 EMF 類型


          第三個(gè)問題如下:

          假設(shè)我們定義了一個(gè)TestInterface接口,并且有一個(gè)實(shí)現(xiàn)類,TestInterfaceImpl,現(xiàn)在我們的某一個(gè)客戶端只擁有TestInterface這個(gè)接口類,而TestInterfaceImpl是在服務(wù)端的。所以在客戶端中,是找不到有關(guān) TestInterface 的實(shí)現(xiàn)的,所以這里使用了 Java 的動(dòng)態(tài)接口代理。利用 Proxy ,在用戶調(diào)用的時(shí)候,采用 Axis 的客戶端代碼訪問 Web Service 。

          ?

          4 .遠(yuǎn)程服務(wù)使用示例
          先下載UxSCA包。
          新的UxSCA是和Tomcat幫定在了一起,它作為一個(gè)Tomcat的webapp存在。在Tomcat啟動(dòng)的時(shí)候會(huì)去查詢定義的Module以及定義的服務(wù)。當(dāng)前UxSCA版本并不是完整的版本,只是為了測(cè)試遠(yuǎn)程服務(wù)而做的,在以后會(huì)完善改進(jìn)。

          下載地址(壓縮包分成了三份):
          Balto1

          Balto2

          Balto3
          準(zhǔn)備環(huán)境:Eclipse-WTP 1.0
          先將下載好的帶有UxSCA的Tomcat釋放到某個(gè)目錄下。
          選擇Eclipse的首選項(xiàng)(Preferences...),增加一個(gè)Server Runtime,路徑指定到下栽好的Tomcat:

          balto1.JPG?

          然后在webapps中找到一個(gè)balto.war,并倒入到Eclipse工程中。

          如果讀者不是在WTP下調(diào)試,則不需要倒入。

          然后新建立一個(gè)Java工程,命名為RemoteProject。

          在該工程下建立一個(gè)XSD文件:Element.xsd,
          這個(gè)Schema比較簡(jiǎn)單,只有一個(gè)元素:Element,Element有兩個(gè)屬性:name,age:

          ?

          <? xml?version="1.0"?encoding="UTF-8" ?>
          < schema? xmlns ="http://www.w3.org/2001/XMLSchema"
          ????targetNamespace
          ="http://www.example.org/Element"
          ????xmlns:tns
          ="http://www.example.org/Element" >
          ????
          < element? name ="Element" >
          ????????
          < complexType >
          ????????????
          < attribute? name ="name" ?type ="string" ></ attribute >
          ????????????
          < attribute? name ="age" ?type ="int" ></ attribute >
          ????????
          </ complexType >
          ????
          </ element >
          </ schema >

          選擇這個(gè)Schema點(diǎn)擊右鍵,選擇新建一個(gè)EMF Model:

          balto2.JPG

          然后根據(jù)向?qū)梢粋€(gè)Element.genmodel文件,打開這個(gè)文件后會(huì)出現(xiàn)一個(gè)編輯界面,選中根元素后點(diǎn)右鍵,選擇:Set SDO Defaults:

          emfmodel.JPG

          然后選擇Generate Model Code,完成后我們發(fā)現(xiàn)在src下多出了一堆代碼,這就是SDO模型代碼:

          modelcode.JPG

          然后修改一下生成的代碼:打開生成的ElementPackageImpl類,找到createExtendedMetaDataAnnotations方法,將

          addAnnotation
          ??????????(elementTypeEClass,?
          ???????????source,?
          ???????????
          new ?String[]?{
          ?????????????
          " name " ,? " Element_._type " ,
          ?????????????
          " kind " ,? " empty "
          ???????????});

          該成:

          addAnnotation
          ??????????(elementTypeEClass,?
          ???????????source,?
          ???????????
          new ?String[]?{
          ?????????????
          " name " ,? " Element " ,
          ?????????????
          " kind " ,? " empty "
          ???????????});

          改這段代碼的目的是為了讓EMF序列化模型的時(shí)候生成的XML片段準(zhǔn)確一點(diǎn),也就是Element_._type元素名要改成Element.

          這里需要注意,如果我們生成SDO代碼是由Ecore生成的,就不會(huì)有上述的問題,如果是以XSD生成的就會(huì)出現(xiàn)這種情況。

          然后我們還需要改一些其他代碼,找到initializePackageContents方法:

          initEClass(documentRootEClass,?DocumentRoot. class ,? " DocumentRoot " ,? ! IS_ABSTRACT,? ! IS_INTERFACE,?IS_GENERATED_INSTANCE_CLASS);
          .....
          initEClass(elementTypeEClass, ElementType.class, "ElementType", !IS_ABSTRACT, !IS_INTERFACE, IS_GENERATED_INSTANCE_CLASS);


          將上面代碼修改為:

          initEClass(documentRootEClass,?DocumentRootImpl. class ,? " DocumentRoot " ,? ! IS_ABSTRACT,? ! IS_INTERFACE,?IS_GENERATED_INSTANCE_CLASS);
          .....
          initEClass(elementTypeEClass, ElementTypeImpl.class, "ElementType", !IS_ABSTRACT, !IS_INTERFACE, IS_GENERATED_INSTANCE_CLASS);


          改這段代碼的目的是為了讓UxSCA能認(rèn)出我們的復(fù)雜類型是一個(gè)SDO模型。因?yàn)樵赨xSCA在遇到EMF模型時(shí)候,會(huì)去查看這個(gè)

          EClass的instance類是否是一個(gè)SDO模型,但是在EMF生成的代碼中,EClass的instance類是一個(gè)接口類,而且該接口類沒有

          實(shí)現(xiàn)EObject以及DataObject。當(dāng)然,這是UxSCA的一個(gè)局限性,在以后的版本中我會(huì)改進(jìn)的。


          現(xiàn)在我們已經(jīng)生成了我們的數(shù)據(jù)對(duì)象,在該工程下建立一個(gè)接口:MyRemotableService,該接口具有兩個(gè)方法:getElement和

          getName,getElement返回的是我們剛才生成的ElementTypeImpl對(duì)象,getName返回的是一個(gè)String。然后我們將這個(gè)類

          利用SCA的Annotation定義為一個(gè)Remotable:

          package ?org.uxteam.sca.example;

          import
          ?org.example.element.impl.ElementTypeImpl;
          import
          ?org.osoa.sca.annotations.Remotable;

          @Remotable
          public ? interface
          ?MyRemotableService?{
          ????ElementTypeImpl?getElement();
          ????String?getName();
          }



          然后我們創(chuàng)建一個(gè)類,讓這個(gè)類實(shí)現(xiàn)MyRemotableService接口,并且將它定義成一個(gè)Service:

          @Service(MyRemotableService. class )
          public ? class ?MyRemotableServiceImpl? implements
          ?MyRemotableService?{

          ????
          /*
          ?(non-Javadoc)
          ?????*?@see?org.uxteam.sca.example.MyRemotableService#getElement()
          ?????
          */

          ????
          public ?ElementTypeImpl?getElement()?{
          ????????ElementTypeImpl?element?
          =
          ?(ElementTypeImpl)?ElementFactory.eINSTANCE.createElementType();
          ????????element.setAge(
          10
          );
          ????????element.setName(
          " Element?Name "
          );
          ????????
          return
          ?element;
          ????}
          ????
          /*
          ?(non-Javadoc)
          ?????*?@see?org.uxteam.sca.example.MyRemotableService#getName()
          ?????
          */

          ????
          public ?String?getName()?{
          ????????
          return ? " This?is?a?remotable?service "
          ;
          ????}
          }



          現(xiàn)在我們完成了遠(yuǎn)程服務(wù)的定義了。

          然后我們將RemoteProject中代碼進(jìn)行打包。先選種src文件夾,然后點(diǎn)右鍵,選擇Export,然后選JarFile,根據(jù)提示即可完成打包。我們將這個(gè)命名為Test.jar

          現(xiàn)在打開Tomcat的webapps,會(huì)發(fā)現(xiàn)一個(gè)名為balto的web項(xiàng)目(UxSCA以后的代號(hào)就為balto),

          打開文件夾后會(huì)發(fā)現(xiàn)一個(gè)名位sca-config.xml文件,打開文件,加入這么一段代碼:

          < property?name? = ? " entries " >
          ????????
          < values >
          ????????????
          < value?type="jar" name = "Test.jar"/?>
          ????????</values>
          </property>


          這段代碼的是讓UxSCA找到我們需要加入到SCA容器管理的包的入口,value的名是包名。

          現(xiàn)在我們通過外部的的應(yīng)用程序去訪問這個(gè)服務(wù)。

          首先,我們需要將這個(gè)服務(wù)的接口類MyRemotableService以及SDO的數(shù)據(jù)模型打包,也就是說要給訪問端工程數(shù)據(jù)以及服務(wù)的接口(這里我們不要把MyRemotableService的實(shí)現(xiàn)類打進(jìn)去)。當(dāng)然,可以直接通過訪問web 服務(wù)的方法訪問,這里這么做只是為了測(cè)試UxSCA容器定位服務(wù)的功能。

          然后我們?cè)傩陆ㄒ粋€(gè)web項(xiàng)目,TestProject,將剛打好的包放到其中。并在這個(gè)項(xiàng)目下創(chuàng)建一個(gè)Servlet

          testservlet.JPG


          在doGET中寫如以下代碼:

          ???? protected ? void ?doGet(HttpServletRequest?request,
          ????????????HttpServletResponse?response)?
          throws
          ?ServletException,?IOException?{
          ????????ModuleContext?context?
          =
          ?CurrentModuleContext.getContext();
          ????????MyRemotableService?service?
          =
          ?(MyRemotableService)?context
          ????????????????.locateService(
          " MyRemotableService "
          );

          ????????ElementTypeImpl?obj?
          =
          ?service.getElement();
          ????????String?name?
          =
          ?obj.getName();
          ????????
          ????????System.out.println(name);
          ????????System.out.println(obj.getName());
          ????????System.out.println(obj.getAge());
          ????}


          然后我們?cè)贓clipse的Servers視圖下建立一個(gè)server:并把我們剛才新建的TestProject和倒入的balto加入進(jìn)去:

          servers.JPG



          然后啟動(dòng)Tomcat,在Console上我們會(huì)發(fā)現(xiàn)這么一段話:

          解析Java?Annotation?得到一個(gè)Service?-?org.uxteam.sca.example.MyRemotableServiceImpl
          解析Java?Annotation得到一個(gè)Service的Java實(shí)現(xiàn)?-?Service?:?MyRemotableService?JavaImplemention?:?org.uxteam.sca.example.MyRemotableServiceImpl
          為遠(yuǎn)程服務(wù)MyRemotableService創(chuàng)建WSDL文件.
          遠(yuǎn)程服務(wù)MyRemotableServiceWSDL文件創(chuàng)建完成
          注冊(cè)遠(yuǎn)程服務(wù)到Axis?wsdd文件中MyRemotableService


          這就說明我們的服務(wù)已經(jīng)被發(fā)現(xiàn),并且UxSCA已經(jīng)將該服務(wù)發(fā)布成了遠(yuǎn)程服務(wù)。

          現(xiàn)在我們?cè)跒g覽器中寫訪問這個(gè)服務(wù):

          http://localhost:8080/balto/services/MyRemotableService

          axis.JPG

          如果看到上面的這個(gè)界面,就說明MyRemotableService已經(jīng)通過Axis被注冊(cè)成為一個(gè)Web Service了。

          現(xiàn)在在瀏覽器中輸入:http://localhost:8080/TestProject/TestServlet

          得到以下結(jié)果:

          teset.JPG

          ?

          5??偨Y(jié)

          SCA的遠(yuǎn)程服務(wù)是銜接模塊和模塊的重要元素,它使得模塊和模塊之間有了交互。當(dāng)遠(yuǎn)程服務(wù)配合上Scope以及回掉接口(異步時(shí)候的接口),將會(huì)發(fā)揮巨大的威力。

          在該稿發(fā)布之時(shí),我的UxSCA中遠(yuǎn)程服務(wù)部分在處理復(fù)雜類型數(shù)據(jù)的時(shí)候出現(xiàn)了一些問題,所以目前還只能是定義單個(gè)元素的復(fù)雜類型(不能使用數(shù)組),并且調(diào)用方法必須是無參數(shù)的。希望不是什么大問題,我會(huì)及時(shí)改正。


          評(píng)論

          # re: SCA程序設(shè)計(jì)——遠(yuǎn)程服務(wù),以及遠(yuǎn)程服務(wù)實(shí)現(xiàn)的一些問題和想法  回復(fù)  更多評(píng)論   

          2006-09-14 18:36 by 冰川
          很好的東西
          謝謝啊。

          # re: SCA程序設(shè)計(jì)——遠(yuǎn)程服務(wù),以及遠(yuǎn)程服務(wù)實(shí)現(xiàn)的一些問題和想法  回復(fù)  更多評(píng)論   

          2007-01-18 19:48 by coolfish
          SCA的遠(yuǎn)程服務(wù),類似這樣的服務(wù)應(yīng)該是可以通過ESB這樣的基礎(chǔ)設(shè)施來達(dá)到目的的吧
          主站蜘蛛池模板: 汝阳县| 锦州市| 红原县| 濉溪县| 门头沟区| 静宁县| 巩义市| 南平市| 东兰县| 武邑县| 宁安市| 佳木斯市| 仪陇县| 三台县| 屯昌县| 房产| 互助| 宁强县| 电白县| 兴仁县| 都江堰市| 洪雅县| 永安市| 原平市| 南江县| 上思县| 达拉特旗| 兴安盟| 郧西县| 临汾市| 舞阳县| 韩城市| 绥宁县| 洛南县| 根河市| 蓬莱市| 兴宁市| 德阳市| 府谷县| 延安市| 九龙城区|