2012-05-24 68 views
3

上下文:應用程序服務器是Glassfish 3.1.2。技術是JavaEE JAX-WS。 IDE是Netbeans 7.1.1。如何從另一個Web服務調用一個Web服務(在同一個WAR中)

我已經使用wsimport從WSDL開始創建了2個Web服務。 EJB也不是。他們都使用@WebService註釋。他們都生活在同一個WAR中(不確定這應該是相關的,但可能是)。我可以非常愉快地單獨部署和測試兩種服務,使用SOAP-UI作爲客戶端。

我現在想讓WebService1在運行時調用WebService2。我不想只使用java調用webservice2的impl(本地可以這麼說) - 我想正確調用webservice2作爲web服務,以便創建一個更鬆散的耦合。

在IDE中,我可以使用提供的「生成代碼:Web服務調用操作」功能爲Web服務調用生成所需的代碼。這增加了一個@WebServiceRef(wsdlLocation =「WEB-INF/wsdl/servicename.wsdl」)和一些代碼來創建一個端口並調用目標web服務操作。

// Call Web Service Operation 
    Identity port = service.getIdentityPort(); 
    String req = ""; 
    javax.xml.ws.Holder<StructureMessageHeader> idHeader = new javax.xml.ws.Holder<StructureMessageHeader>(); 
    String result = port.getIdentifier(req, idHeader); 

這編譯得很好,但在運行時卻失敗了。部署是成功的,而服務是向上和一般單獨快樂(只要你不把這個代碼),但是,當一個Web服務嘗試調用其他的我得到一個

ClientTransportException: The server sent HTTP status code 404: Not Found.

進一步詳情如下。

有誰知道爲什麼會發生這種情況?我哪裏做錯了?我忽視了什麼?

任何幫助,非常感謝。

------------------------ EXCEPTION ---------------------

com.sun.xml.ws.client.ClientTransportException: The server sent HTTP status code 404: Not Found at com.sun.xml.ws.transport.http.client.HttpTransportPipe.checkStatusCode(HttpTransportPipe.java:321) at com.sun.xml.ws.transport.http.client.HttpTransportPipe.createResponsePacket(HttpTransportPipe.java:270) at com.sun.xml.ws.transport.http.client.HttpTransportPipe.process(HttpTransportPipe.java:228) at com.sun.xml.ws.transport.http.client.HttpTransportPipe.processRequest(HttpTransportPipe.java:143) at com.sun.xml.ws.transport.DeferredTransportPipe.processRequest(DeferredTransportPipe.java:110) at com.sun.xml.ws.api.pipe.Fiber.__doRun(Fiber.java:961) at com.sun.xml.ws.api.pipe.Fiber._doRun(Fiber.java:910) at com.sun.xml.ws.api.pipe.Fiber.doRun(Fiber.java:873) at com.sun.xml.ws.api.pipe.Fiber.runSync(Fiber.java:775) at com.sun.xml.ws.api.pipe.helper.AbstractTubeImpl.process(AbstractTubeImpl.java:116) at com.sun.enterprise.security.webservices.ClientSecurityPipe.processSecureRequest(ClientSecurityPipe.java:196) at com.sun.enterprise.security.webservices.ClientSecurityPipe.process(ClientSecurityPipe.java:184) at com.sun.xml.ws.api.pipe.helper.PipeAdapter.processRequest(PipeAdapter.java:119) at com.sun.xml.ws.api.pipe.Fiber.__doRun(Fiber.java:961) at com.sun.xml.ws.api.pipe.Fiber._doRun(Fiber.java:910) at com.sun.xml.ws.api.pipe.Fiber.doRun(Fiber.java:873) at com.sun.xml.ws.api.pipe.Fiber.runSync(Fiber.java:775) at com.sun.xml.ws.client.Stub.process(Stub.java:429) at com.sun.xml.ws.client.sei.SEIStub.doProcess(SEIStub.java:168) at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:119) at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:102) at com.sun.xml.ws.client.sei.SEIStub.invoke(SEIStub.java:151) at $Proxy219.getIdentifier(Unknown Source) at com.soagrowers.r20121231.product.master.services.ProductsEntityService.createProduct(ProductsEntityService.java:138) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.glassfish.webservices.InstanceResolverImpl$1.invoke(InstanceResolverImpl.java:143) at com.sun.xml.ws.server.InvokerTube$2.invoke(InvokerTube.java:149) at com.sun.xml.ws.server.sei.SEIInvokerTube.processRequest(SEIInvokerTube.java:94) at com.sun.xml.ws.api.pipe.Fiber.__doRun(Fiber.java:961) at com.sun.xml.ws.api.pipe.Fiber._doRun(Fiber.java:910) at com.sun.xml.ws.api.pipe.Fiber.doRun(Fiber.java:873) at com.sun.xml.ws.api.pipe.Fiber.runSync(Fiber.java:775) at com.sun.xml.ws.api.pipe.helper.AbstractTubeImpl.process(AbstractTubeImpl.java:116) at org.glassfish.webservices.MonitoringPipe.process(MonitoringPipe.java:142) at com.sun.xml.ws.api.pipe.helper.PipeAdapter.processRequest(PipeAdapter.java:119) at com.sun.xml.ws.api.pipe.Fiber.__doRun(Fiber.java:961) at com.sun.xml.ws.api.pipe.Fiber._doRun(Fiber.java:910) at com.sun.xml.ws.api.pipe.Fiber.doRun(Fiber.java:873) at com.sun.xml.ws.api.pipe.Fiber.runSync(Fiber.java:775) at com.sun.xml.ws.api.pipe.helper.AbstractTubeImpl.process(AbstractTubeImpl.java:116) at com.sun.enterprise.security.webservices.CommonServerSecurityPipe.processRequest(CommonServerSecurityPipe.java:212) at com.sun.enterprise.security.webservices.CommonServerSecurityPipe.process(CommonServerSecurityPipe.java:144) at com.sun.xml.ws.api.pipe.helper.PipeAdapter.processRequest(PipeAdapter.java:119) at com.sun.xml.ws.api.pipe.Fiber.__doRun(Fiber.java:961) at com.sun.xml.ws.api.pipe.Fiber._doRun(Fiber.java:910) at com.sun.xml.ws.api.pipe.Fiber.doRun(Fiber.java:873) at com.sun.xml.ws.api.pipe.Fiber.runSync(Fiber.java:775) at com.sun.xml.ws.server.WSEndpointImpl$2.process(WSEndpointImpl.java:386) at com.sun.xml.ws.transport.http.HttpAdapter$HttpToolkit.handle(HttpAdapter.java:640) at com.sun.xml.ws.transport.http.HttpAdapter.handle(HttpAdapter.java:263) at com.sun.xml.ws.transport.http.servlet.ServletAdapter.handle(ServletAdapter.java:163) at org.glassfish.webservices.JAXWSServlet.doPost(JAXWSServlet.java:145) at javax.servlet.http.HttpServlet.service(HttpServlet.java:688) at javax.servlet.http.HttpServlet.service(HttpServlet.java:770) at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1542) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:281) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175) at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655) at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:161) at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:331) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:231) at com.sun.enterprise.v3.services.impl.ContainerMapper$AdapterCallable.call(ContainerMapper.java:317) at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:195) at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:849) at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:746) at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1045) at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:228) at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137) at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104) at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90) at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79) at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54) at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59) at com.sun.grizzly.ContextTask.run(ContextTask.java:71) at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532) at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513) at java.lang.Thread.run(Thread.java:662)

回答

2

我想我已經固定它

有2個問題,並修復這些錯誤後,我的代碼現在的工作,因爲它應該。

問題#1。 (次要) jax-ws-catalog.xml不包含對WebService2的WSDL或XSD文件的引用。這需要幫助JAX-WS框架在運行時利用WSDL的本地副本,而無需通過HTTP加載WSDL或XSD。

問題#2。 (主要) jax-ws-catalog中引用的WSDL中的'Service'部分需要在其中包含精確的端點位置。在運行時,服務器會根據各種配置(如@webservice註釋中的詳細信息)將WSDL的這一位重寫爲服務的正確http端點位置。當然,當你從WSDL開始時,這個端點可能是完全不明智的,因爲服務契約與任何實現都是分離的(就像我的情況一樣)。因此,當JAX-WS從jax-ws-catalog中指定的位置拾取WSDL時,它會找到一個不存在並且無法解析的http位置。因此,「ClientTransportException: The server sent HTTP status code 404: Not Found.」 - WSDL中的URL出錯。

總結。 解決的辦法是爲Web服務添加一個精確的端點位置到WSDL的「服務」定義部分,並確保WSDL及其XSD在jax-ws-catalog中正確列出。

1

人們需要嵌入一個web客戶端到所述第一web服務,該服務然後請求從所述第二web服務的信息。 This client from apache已使用,效果良好。

有時,Web服務庫還包含一個嵌入式Web客戶端,以方便測試。如果您的libararies包含這樣的客戶端,那麼您甚至不需要添加額外的Web客戶端實現。

---編輯,以回答問題有關,如果JAXWS API提供的「客戶」的支持---

當然JAXWS擁有一切,建立一個Web服務,但我不確定它是否是部分該規範還包含調用Web服務的所有內容。我還沒有看到缺乏這種設施的實施,因此,「偶爾」對圖書館中包含客戶的迴應有點過分誇大其缺失的可能性。

在任何情況下,支持客戶端的類都簡單地包裝XML生成器和HTTP客戶端。

如果內存正確地爲我提供服務,您將獲得WSDL的副本,該副本由在編譯器名稱空間中輸出Java源代碼的「編譯器」讀取。然後使用生成的類,您可以訪問遠程Web服務的API級別。最終的結果看起來是這樣的

public static void main(String[] args) { 
    /* Create the service instance */ 
    CalculatorService service = new CalculatorService(); 
    CalculatorDelegate delegate = service.getCalculatorPort(); 

    /* Using the web service, perform the 4 calculations */ 
    System.out.println("1. 3+7=" + delegate.add(3, 7)); 
    System.out.println("2. 12-2=" + delegate.subtract(12, 2)); 
    System.out.println("3. 9*9=" + delegate.multiply(9, 9)); 
    System.out.println("4. 40/2=" + delegate.divide(40, 2)); 
} 

當你創建「服務的客戶視圖」通過構建XXXService對象,然後附加到它產生類型XXXDelegate的委託對象。委託中的方法實際上會生成新對象(每個綁定了「SomeCall.java」的端口都存在一個對象),該對象封裝了請求,並且響應由一個「SomeCallReply.java」文件處理,委託隨後用它來解包該響應並將該值返回給「客戶」代碼。

可以找到一個例子at the bottom of this tutorial。再次,這是我對高層次內容的理解,JAXWS新版本中的細節可能已經發生了變化。當我深入挖掘時,這在遊戲中很早。自那以後,JAXWS發佈了很多。

+0

我想我明白你的意思,但是你有一個參考你可以指點我嗎? – benwilcock

+0

我確信JAX-WS框架可以提供我需要的其他服務而不必訴諸於其他HTTP框架的所有東西。這是不是真的? – benwilcock

+0

據我所知,這是真的,但我不知道這是否是真的,如果我誇大了「有時」,我很抱歉。再讀一遍,我可以很容易地看到我是如何暗示它很少是真的。對困惑感到抱歉。 –

1

解決這個問題的一種更好的方法是使Web服務成爲一個層,然後調用到應用程序邏輯中。然後,當一組業務邏輯需要調用另一組業務時,它不必經歷不必要的http往返。考慮使用類似Spring的@Service和@Autowired。在EJB世界中(我知道你說你沒有使用它),這是通過@Local接口和@EJB會話注入來完成的,所以你不會通過一個巨大的遠程API堆棧來調用另一個類中的方法。

+0

我正在嘗試應用合同集中SOA模式,該模式主張服務合同應該是客戶使用服務的唯一方式。這是通過避免直接消費者實現耦合(例如直接到EJB)來實現更鬆散耦合的一種方式。 – benwilcock

+0

我並不是主張客戶直接與Spring'@ Service'或'@ Stateless'會話bean進行對話。我所說的業務邏輯應該被認爲是Web層與之交談的一項服務。然後,給定的Web服務調用一個業務服務,不知道該業務服務在內部執行什麼操作。商業服務可以是商業服務的組成部分。 – Jim

相關問題