如何从另一个Web服务调用一个Web服务(在同一个WAR中)

时间:2012-05-24 14:58:58

标签: java web-services glassfish jax-ws

上下文: Application Server是Glassfish 3.1.2。技术是JavaEE JAX-WS。 IDE是Netbeans 7.1.1。

我使用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”)和一些代码来创建一个端口并调用目标webservice操作。

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

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)

3 个答案:

答案 0 :(得分: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目录中正确列出。

答案 1 :(得分:1)

需要将Web客户端嵌入到第一个Web服务中,然后第一个Web服务要求提供来自第二个Web服务的信息。 This client from apache已被使用,效果很好。

有时,Web服务库还包含一个嵌入式Web客户端,以方便测试。如果您的图书馆包含这样的客户端,您甚至不需要添加额外的Web客户端实现。

---编辑回答有关JAXWS API是否提供“客户端”支持的问题---

当然JAX-WS拥有设置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已经发布了很多版本。

答案 2 :(得分:1)

更好的方法是使Web服务成为一个层,然后调用应用程序逻辑。然后当一组业务逻辑需要调用另一组时,它不必经过不必要的http往返。考虑使用像@Service和@Autowired这样的Spring。在EJB世界中(我知道你说你没有使用它),这是通过@Local接口和@EJB会话注入完成的,因此你不会通过一个巨大的远程API栈来调用另一个类中的方法。 / p>