CXF Frontends的使用

概覽


CXF frontends 是一組編程的API看铆,被用來開發(fā)和發(fā)布webservice沾瓦。CXF支持兩種類型的frontend--JAX-WS和簡單frontend褥伴。這章將對JAX-WS frontend提供更加詳細的解釋返吻。我們同樣也會展示如何使用簡單frontend API來構(gòu)建一個webservice萧恕。這個章節(jié)將會關(guān)注使用如下兩種frontend來開發(fā)基于SOAP的web服務(wù):

  • JAX-WS frontend
  • 簡單 frontend

關(guān)于JAX-WS frontend刚梭,我們將說明如下內(nèi)容:

  • 使用編碼優(yōu)先的開發(fā)方式來開發(fā)webservice
  • 使用契約優(yōu)先的開發(fā)方式來開發(fā)webservice
  • 構(gòu)建一個動態(tài)客戶端或消費者
  • 基于Provider and Dispatch的實現(xiàn)
  • 理解webservice上下文

JAX-WS frontend


CXF支持由Java Community Process(JCP)提供的JAX-WS 2.0 API 規(guī)范肠阱。JAX-WS是一個由JCP制訂的正式規(guī)范,它定義了API用來構(gòu)建朴读,開發(fā)和部署webservice屹徘。CXF提供了它自己的JAX-WS實現(xiàn)來附加在JAX-WS標準規(guī)范上。CXF JAX-WS frontend為構(gòu)建不同種類的webservice提供了不公的API衅金。拋開提供標準的基于WSDL的開發(fā)不講噪伊,它還在Provider and Dispatch接口的形式中提供了用于構(gòu)建基于XML服務(wù)的API。

有兩種方式來開發(fā)基于SOAP的JAX-WS webservice-編碼優(yōu)先契約優(yōu)先氮唯。正如名字顯示的那樣鉴吹,在編碼優(yōu)先的開發(fā)模式中,你將從編碼開始惩琉,然后將它轉(zhuǎn)化成WSDL豆励。編碼優(yōu)先的開發(fā)方式適用于:在實現(xiàn)方法的輸入和輸出的對象格式較簡單時,并且你想要將它們快速地暴露為webservice的時候瞒渠。編碼優(yōu)先的開發(fā)方式是更簡單的良蒸,因為你將從Java對象開始,而不必考慮如何生成WSDL和XSD在孝,而這個過程會在Java對象無法被按照你的意愿映射到XML元素的時候?qū)е乱恍﹩栴}诚啃。注意,像CXF Java2WSDL 這樣基于實現(xiàn)方法的輸入輸出格式的工具私沮,將會生成契約始赎,包括為你生成XSD格式。比如仔燕,你不能暴露一個Map或者Collection作為一個輸出信息格式造垛,因為沒有標準的做法將它映射到XML schema,而這將會導致交互上的問題晰搀。

契約優(yōu)先的開發(fā)方式中五辽,開發(fā)者從一個已經(jīng)存在的WSDL artifact來構(gòu)建webservice。契約優(yōu)先的開發(fā)方式適用于:當你已經(jīng)有了一個XML schema為webservice的操作定義了輸入輸出消息的格式的時候外恕,或者想要更好的控制XML如何被映射到Java對象的時候杆逗。契約優(yōu)先的開發(fā)方式需要你很精通XSD和WSDL契約,因為你將使用這些契約開始創(chuàng)建你的model鳞疲。如果你在創(chuàng)建基于工業(yè)標準的服務(wù)罪郊,你或許需要從契約優(yōu)先的開發(fā)方式開始,因為工業(yè)消息的格式通常是XML schema的尚洽。

如果兩種方式你都熟悉悔橄,并且知道對象是如何映射到XML的,你可以使用編碼優(yōu)先的開發(fā)方式。CXF不僅支持這些開發(fā)方式癣疟,而且為多種數(shù)據(jù)綁定機制提供了支持挣柬,這些機制將幫助你把Java對象映射到XML。

我們將從編碼優(yōu)先的開發(fā)方式開始睛挚。

編碼優(yōu)先的開發(fā)方式


在這個部分邪蛔,我們將以開發(fā)一個Java類,并且通過注解它將它轉(zhuǎn)化成一個service類開始竞川。你將遵循如下的步驟完成webservice的開發(fā):

  • 創(chuàng)建Service Endpoint Interface(SEI)
  • 添加Java注解
  • 發(fā)布服務(wù)
  • 開發(fā)一個消費者
  • 運行編碼優(yōu)先的例子

創(chuàng)建Service Endpoint Interface(SEI)

Service Endpoint Interface是一個Java接口店溢,它定義了一個被用來暴露為服務(wù)的業(yè)務(wù)方法。這個服務(wù)方法被一個服務(wù)類實現(xiàn)委乌。一個SEI可以通過兩種不同的方式來構(gòu)建:

  • 從零構(gòu)建一個SEI組件
  • 將存在的業(yè)務(wù)功能轉(zhuǎn)化成基于服務(wù)的組件

第一個方式--從零構(gòu)建一個SEI組件的方式是指床牧,開發(fā)一個全新的webservice而不依賴于任何已經(jīng)存在的代碼或WSDL契約。它推薦你從寫服務(wù)接口開始遭贸,然后創(chuàng)建這個服務(wù)的實現(xiàn)類戈咳。寫服務(wù)接口總是好的實踐,因為它為你的服務(wù)方法提供了一個適當?shù)目蛻舳艘晥D壕吹。之后著蛙,實現(xiàn)類可以實現(xiàn)定義在接口中的方法。

第二個方式是指耳贬,拿到已經(jīng)存在的業(yè)務(wù)功能踏堡,然后把它轉(zhuǎn)化成基于服務(wù)的組件。大多數(shù)時候咒劲,你已經(jīng)開發(fā)過了業(yè)務(wù)邏輯顷蟆,你只是想把它們作為服務(wù)方法暴露出去。你可以通過如下的方式來完成這個過程:開發(fā)一個SEI腐魂,并只定義那些你想要暴露成為一個服務(wù)方法的業(yè)務(wù)方法帐偎,然后使已經(jīng)存在的Java代碼實現(xiàn)那個SEI。另一個常用的方式是:創(chuàng)建包裝后的SEI和一個實現(xiàn)類蛔屹,這個實現(xiàn)類可以使用已經(jīng)存在的實現(xiàn)類來完成自己的功能削樊。

我們將從零創(chuàng)建一個SEI組件開始。我們開發(fā)一個OrderProcessSEI并且實現(xiàn)它兔毒。下面的代碼顯示了這個OrderProcessSEI:

package demo.order;
public interface OrderProcess {
    String processOrder(Order order);
}

你可以看到漫贞,上面的代碼是一個簡單的POJO接口。它定義了一個抽象方法processOrder育叁,它接收一個Orderbean作為一個參數(shù)绕辖。OrderProcessImpl實現(xiàn)類實現(xiàn)了processOrder方法,并且這個方法將在之后作為一個webservice方法暴露出來擂红。

我們接下來將實現(xiàn)這個接口的業(yè)務(wù)邏輯。你將要寫這個OrderProcessImpl來實現(xiàn)OrderProcessSEI。下面的代碼顯示這個OrderProcessImpl類:

package demo.order;
public class OrderProcessImpl implements OrderProcess {
    public String processOrder(Order order) {
        System.out.println("Processing order...");
        String orderID = validate(order);
        return orderID;
    }
}

上面的代碼是一個簡單的POJO實現(xiàn)類昵骤,它實現(xiàn)類processOrder方法树碱。這個方法簡單地校驗了訂單,并返回一個唯一的訂單ID变秦。簡單起見成榜,我們返回了一個靜態(tài)的訂單ID作為我們實現(xiàn)的一部分。在下一個部分蹦玫,我們將通過注解它們的方式把SEI和實現(xiàn)類轉(zhuǎn)化成為webservice組件赎婚。

添加Java注解

Webservice注解被添加到一個Java類用來將其暴露成為一個服務(wù)組件。JAX-WS使用Java 5注解樱溉,它是Web Services Metadata為Java Platform規(guī)范(JSR-181)提供的挣输,用來將一個組件轉(zhuǎn)化成為一個webservice。這些注解簡單地標記福贞,被用來為一個特定的組件或者方法定義一個特定上下文撩嚼。每一個注解被一個或多個上下文的屬性所支持。在這個部分挖帘,我們將向我們的OrderProcessSEI和實現(xiàn)類添加注解完丽,并將它們轉(zhuǎn)化成一個服務(wù)組件。在這個部分拇舀,我們將覆蓋如下的webservice注解:

  • javax.jws.WebService
  • javax.jws.soap.SOAPBinding
javax.jws.WebService

一個Java組件可以通過添加一個@WebService注解的方式被轉(zhuǎn)化成為一個服務(wù)逻族。這個注解必須被同時定義在SEI和實現(xiàn)類中。@WebService注解被定義在javax.jws.WebService接口骄崩。

@WebService注解支持如下的屬性:

@WebService注解支持的屬性

讓我們注解我們的OrderProcessSEI和OrderProcessImpl實現(xiàn)類聘鳞。下面的代碼展示了@WebService注解的使用:

package demo.order;
import javax.jws.WebService;
@WebService
public interface OrderProcess {
    String processOrder(Order order);
}

@WebService被直接聲明在接口或者類之上。它注解了這個類或者接口作為一個webservice的類或者接口刁赖。在上面的代碼中搁痛,OrderProcess接口通過@WebService注解,來被定義成為一個webservice接口宇弛。

讓我們看一下OrderProcessImpl實現(xiàn)類鸡典。下面的代碼展示了被注解的OrderProcessImpl實現(xiàn)類:

package demo.order;
import javax.jws.WebService;
@WebService(serviceName="OrderProcessService", 
    portName="OrderProcessPort")
public class OrderProcessImpl implements OrderProcess {
    public String processOrder(Order order) {
        System.out.println("Processing order...");
        String orderID = validate(order);
        return orderID;
    }
}

和SEI類似,你在類之上聲明@WebService枪芒。你將定義兩個屬性--serviceNameportName彻况。serviceName屬性被賦值為OrderProcessService。這個服務(wù)名稱被消費者用來獲取遠程接口的句柄來調(diào)用服務(wù)方法舅踪。端口名稱簽名了endpoint名稱纽甘。服務(wù)的endpoint也同樣作為一個服務(wù)端口在服務(wù)發(fā)布的地方被調(diào)用。這里的名字是OrderProcessPort抽碌。

有許多其它可選的注解被用來和@WebService搭配使用悍赢,用來更加完整地描述一個webservice。其它注解可以添加更精細的細節(jié)到一個服務(wù)上∽笕ǎ總是推薦你使用這些注解來描述你的webservice皮胡,以便于生成的WSDL文檔有更多的被這些注解指定的細節(jié)。如果你沒有使用這些可選的注解赏迟,那么WSDL將被按照默認的規(guī)則生成屡贺,正如前面表格中討論的一樣。

javax.jws.soap.SOAPBinding

@SOAPBinding注解被定義在javax.jws.soap.SOAPBinding接口中锌杀。這個注解在你想要為你的服務(wù)制定SOAP綁定的時候使用甩栈。

這個注解支持如下的屬性:

@SOAPBinding注解支持的屬性

SOAP綁定在webservice交互中扮演著重要的角色。讓我們更加詳細地看看兩種風格的SOAP綁定糕再。

RPC 風格 v.s Document 風格

Webservice的SOAP交互風格在服務(wù)提供者和消費者之間交互SOAP XML消息中扮演著重要的角色量没。有兩種SOAP消息風格--DocumentRPC。SOAP消息的風格被作為SOAP綁定定義在WSDL文檔中亿鲜。一個SOAP綁定能夠擁有一個基于編碼的使用(encoded use) 或者 基于字面的使用(encoded use or a literal use)允蜈。編碼,這個詞暗示了消息將使用某種格式被編碼蒿柳,而字面的表示使用純文本消息饶套,而不做任何編碼邏輯。

正如名字顯示的那樣垒探,Document風格將XML文檔作為有效的載荷來添加到定義良好的契約中妓蛮,通常的做法是使用XML schema定義來創(chuàng)建。XML schema格式指定了被消費者調(diào)用的服務(wù)消息的契約圾叼。XML schema定義了服務(wù)提供者和服務(wù)消費者之間的request和response消息的格式蛤克。這些消息的格式可以被服務(wù)的提供者和消費者驗證為合法。Document literal風格對webservice交互來完成協(xié)作來說是更受歡迎的方式夷蚊。

另一方面构挤,RPC(Remote Procedure Call)風格表明了SOAP主體包含一個XML的方法展示。為了序列化方法的參數(shù)到SOAP消息惕鼓,以便于它能夠被任何webservice實現(xiàn)反序列化筋现。SOAP規(guī)范定義了一系列的編碼規(guī)則。由于RPC通常被用在連接SOAP的編碼規(guī)則箱歧,這個連接將被引用為RPC/encoded矾飞。你用養(yǎng)有一種RPC/literal交互風格模式,這種模式中你沒有任何的編碼格式呀邢,但是消息依然受限于RPC 基于方法的交互洒沦,這種方式下,消息不能被驗證為合法的价淌,因為他們與任何XML schema定義之間都沒有關(guān)聯(lián)申眼。你或許應該避免開發(fā)RPC風格的webservice瞒津,因為它們有許多協(xié)作性上的問題。

下面的代碼展示了@SOAPBinding注解的使用:

@WebService(name="OrderProcess")
@SOAPBinding(parameterStyle=ParameterStyle.BARE)
public interface OrderProcess {
    String processOrder(Order order);
}
javax.jws.WebMethod

@WebMethod注解被定義在javax.jws.WebMethod接口中豺型。這個注解被用來自定義webservice的操作仲智。@WebMethod注解提供了operation的nameaction屬性,這兩個屬性分別被用來自定義在WSDL文檔中的<wsdl:operation>元素的name屬性和<soap:operation>元素的soapAction屬性姻氨。@WebMethod注解被放置在服務(wù)方法聲明的上面。

@WebMethod注解支持如下的屬性:

@WebMethod注解支持的屬性

下面的代碼片段展示了@WebMethod注解的使用:

@WebMethod (name="processOrder")
public String processOrder(Order order) {
    // ...
}

JAX-WS webservice注解支持一系列的其它注解剪验,比如:@RequestWrapper, @ResponseWrapper, @Oneway等等肴焊。它們中的一些將稍后解釋。

發(fā)布服務(wù)

發(fā)布服務(wù)意味著將服務(wù)組件注冊到服務(wù)器上功戚,并且通過endpoint URL使其可以被消費者使用娶眷。你將把OrderProcesswebservice發(fā)布到一個特定的endpoint URL上。在本例中的endpoint URL將會是http://localhost:8080/OrderProcess啸臀。你將開發(fā)一個服務(wù)器組件來發(fā)布你的OrderProcess服務(wù)届宠。對這個例子來說,我們將使用Java 5提供的輕量級的web服務(wù)器來發(fā)布我們的服務(wù)乘粒。CXF提供了它自己獨立的服務(wù)器組件--JaxWsServerFactoryBean來發(fā)布webservice豌注。

下面的代碼展示了服務(wù)器代碼:

import javax.xml.ws.Endpoint;
public class Server {
    protected Server() throws Exception {
        System.out.println("Starting Server ...");
        OrderProcessImpl orderProcessImpl = new OrderProcessImpl();
        String address = "http://localhost:8080/OrderProcess";
        Endpoint.publish(address, orderProcessImpl);
    }   
    public static void main(String[] args) {
        new Server();
        Thread.sleep(50000);
        System.exit(0);
    } 
}

用于發(fā)布Endpoint類的靜態(tài)方法提供了一個簡便的方式來發(fā)布和測試JAX-WS webservice。這個方法接受endpoint URL和一個OrderProcessImpl類對象作為參數(shù)灯萍。這個publish方法在URL http://localhost:8080/OrderProcess上創(chuàng)建一個輕量級的web服務(wù)器轧铁,并且在那個位置部署這個服務(wù)。這個輕量級的web服務(wù)器在JVM中運行一分鐘然后自動終止旦棉。一種能夠看到服務(wù)的WSDL契約的方法是在web瀏覽器中訪問這個URL:

http://localhost:8080/OrderProcess?wsdl

開發(fā)一個消費者

webservice的消費者調(diào)用服務(wù)方法來獲得需要的結(jié)果齿风。在這一部分,我們將開發(fā)一個Client類來查找我們的OrderProcess服務(wù)绑洛,并且調(diào)用它的processOrder方法救斑。下面的代碼展示了服務(wù)消費者組件:

public class Client {
    private static final QName SERVICE_NAME =
        new QName("http://order.demo/", "OrderProcessService");
    private static final QName PORT_NAME =
        new QName("http://order.demo/", "OrderProcessPort");
    private static final String WSDL_LOCATION =
        "http://localhost:8080/OrderProcess?wsdl";
    
    public static void main(String args[]) throws Exception {
        URL wsdlURL = new URL(WSDL_LOCATION);
        Service service = Service.create(wsdlURL, SERVICE_NAME);
        OrderProcess port = service.getPort(PORT_NAME, OrderProcess.class);
        Order order = new Order();
        order.setCustomerID("C001");
        order.setItemID("I001");
        order.setPrice(100.00);
        order.setQty(20);
        String result = port.processOrder(order);
        System.out.println("The order ID is " + result);
    }
}

客戶端的代碼做了以下的事情:

  1. 它首先創(chuàng)建了WSDL URL。這個WSDL URL是http://localhost:8080/OrderProcess?wsdl真屯。這個URL表明了WSDL 文檔的位置脸候。

在運行客戶端程序之前,你可以通過訪問以上的URL來驗證這個服務(wù)是否可用讨跟。如果你能夠看見WSDL纪他,那么就意味著這個OrderProcess服務(wù)被成功地發(fā)布了。

  1. 接下來創(chuàng)建了Service對象晾匠。這個Service對象使用了靜態(tài)的create 方法被創(chuàng)建茶袒。這個方法接受WSDL URL和服務(wù)名稱作為參數(shù)。這個服務(wù)名稱OrderProcessService是一個QName凉馆,并且在WSDL文檔中被映射到<wsdl:service>元素薪寓。<wsdl:service>元素定義了服務(wù)的endpoint亡资。
  2. 使用Service對象,你通過調(diào)用getPort方法獲得SEI句柄的代理組件向叉。getPort方法接受port name和SEI類作為參數(shù)锥腻。接口名稱OrderProcessPort是一個QName,并且在WSDL文檔中被映射到<wsdl:port>元素母谎。這個SEI類是OrderProcess瘦黑。
  3. 代理組件在接下來被用來調(diào)用服務(wù)方法processOrder。在調(diào)用方法之前奇唤,你必須安置好Orderbean幸斥,并把它傳給processOrder方法。這個方法在服務(wù)器上被調(diào)用咬扇,并返回訂單ID甲葬。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市懈贺,隨后出現(xiàn)的幾起案子经窖,更是在濱河造成了極大的恐慌,老刑警劉巖梭灿,帶你破解...
    沈念sama閱讀 222,627評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件画侣,死亡現(xiàn)場離奇詭異,居然都是意外死亡胎源,警方通過查閱死者的電腦和手機棉钧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,180評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來涕蚤,“玉大人宪卿,你說我怎么就攤上這事⊥蛘ぃ” “怎么了佑钾?”我有些...
    開封第一講書人閱讀 169,346評論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長烦粒。 經(jīng)常有香客問我休溶,道長,這世上最難降的妖魔是什么扰她? 我笑而不...
    開封第一講書人閱讀 60,097評論 1 300
  • 正文 為了忘掉前任兽掰,我火速辦了婚禮,結(jié)果婚禮上徒役,老公的妹妹穿的比我還像新娘孽尽。我一直安慰自己,他們只是感情好忧勿,可當我...
    茶點故事閱讀 69,100評論 6 398
  • 文/花漫 我一把揭開白布杉女。 她就那樣靜靜地躺著瞻讽,像睡著了一般。 火紅的嫁衣襯著肌膚如雪熏挎。 梳的紋絲不亂的頭發(fā)上速勇,一...
    開封第一講書人閱讀 52,696評論 1 312
  • 那天,我揣著相機與錄音坎拐,去河邊找鬼烦磁。 笑死,一個胖子當著我的面吹牛哼勇,可吹牛的內(nèi)容都是我干的个初。 我是一名探鬼主播,決...
    沈念sama閱讀 41,165評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼猴蹂,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了楣嘁?” 一聲冷哼從身側(cè)響起磅轻,我...
    開封第一講書人閱讀 40,108評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎逐虚,沒想到半個月后聋溜,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,646評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡叭爱,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,709評論 3 342
  • 正文 我和宋清朗相戀三年撮躁,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片买雾。...
    茶點故事閱讀 40,861評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡把曼,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出漓穿,到底是詐尸還是另有隱情嗤军,我是刑警寧澤,帶...
    沈念sama閱讀 36,527評論 5 351
  • 正文 年R本政府宣布晃危,位于F島的核電站叙赚,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏僚饭。R本人自食惡果不足惜震叮,卻給世界環(huán)境...
    茶點故事閱讀 42,196評論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望鳍鸵。 院中可真熱鬧苇瓣,春花似錦、人聲如沸权纤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,698評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至外邓,卻和暖如春撤蚊,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背损话。 一陣腳步聲響...
    開封第一講書人閱讀 33,804評論 1 274
  • 我被黑心中介騙來泰國打工侦啸, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人丧枪。 一個月前我還...
    沈念sama閱讀 49,287評論 3 379
  • 正文 我出身青樓光涂,卻偏偏與公主長得像,于是被迫代替她去往敵國和親拧烦。 傳聞我的和親對象是個殘疾皇子忘闻,可洞房花燭夜當晚...
    茶點故事閱讀 45,860評論 2 361

推薦閱讀更多精彩內(nèi)容