Java EE应用程序之间的Web服务通信

时间:2013-03-27 15:42:33

标签: java web-services java-ee jax-ws

我在两个独立的应用程序服务器上有两个Java EE应用程序。其中一个已经包含一个有效的EJB。我希望能够通过使用JAX-WS Web服务从其他应用程序与此EJB进行通信(通信必须在不同的应用程序服务器和不同的服务器版本之间工作,因此远程EJB调用是不可选的)。将服务器api暴露给客户端应用程序没有问题。 服务器端非常清楚,添加@Webservice注释似乎工作得很好。但我想知道构建客户端的最佳方法是什么:我真的不想从wsdl生成客户端存根(在我的情况下,它本身是由容器的ejb代码生成的)并打包所有这些生成的类进入客户耳朵 - 但这似乎是我可以使用@WebServiceRef注释的唯一方法。

规范不建议在javax.xml.ws.Service的静态方法(类似于service = Service.create()和service.getPort())的帮助下自己创建动态代理的替代方法并且“容器提供程序不需要支持使用这些方法创建的托管服务实例”。 但那恰到好处。我想用的是:

有没有办法在应用服务器管理的代码中注入动态代理?或者是使用生成的客户端存根类来完成托管Web服务客户端实例的唯一方法吗?

1 个答案:

答案 0 :(得分:2)

阅读JAX-WS 2.2规范,第4章:客户端API。

<强> 1。静态客户端生成

使用JAX-WS真的是最简单的方法。从Web服务的角度来看,WSDL是接口和连接属性。即使您选择不在物理上使用它,您仍然需要在逻辑意义上了解它以进行有意义的SOAP调用。

来自JAX-WS规范的注释:使用SOAP 1.1 / HTTP绑定的端点必须 使其合同在发布地址作为WSDL 1.1文档提供,后缀为?WSDL?wsdl

<强> 2。动态客户端编程

  

有没有办法在应用服务器管理的代码中注入动态代理?

这种方法涉及针对JAX-WS API进行动态编程,以便在使用或不使用WSDL的情况下连接到Web服务。没有办法只是“注入”动态代理。你需要构建&amp;使用SEI的端口URL配置一个。 WSDL文档是存储此类配置信息的标准位置,尽管可以避免它并以编程方式插入信息。

  • 2A)使用WSDL进行动态编程:

     javax.xml.ws.Service service = Service.create(
         new URL("http://example.org/stocks.wsdl"),
         new QName("http://example.org/stocks", "StockQuoteService"));
     com.example.StockQuoteProvider proxy = service.getPort(portName,
     com.example.StockQuoteProvider.class)
     javax.xml.ws.BindingProvider bp = (javax.xml.ws.BindingProvider)proxy;
     Map<String,Object> context = bp.getRequestContext();
     context.setProperty("javax.xml.ws.session.maintain", Boolean.TRUE);
     proxy.getLastTradePrice("ACME");
    

    优点超过(1):可以在部署应用程序后动态动态更改WSDL文档,提供此类更改不会影响到客户端的Java接口。

    <强>即。对你没什么好处。您的WSDL是静态的。虽然您可以将客户端指向<service endpoint URL>?wsdl以进行动态查找,但这意味着您需要手动配置<service endpoint URL>并且在SEI / WSDL中不会产生任何可能发生变化的其他内容而不会影响你的客户逻辑。

  • 2B)没有WSDL的动态编程:

    String endpointUrl = ...;           
    QName serviceName = new QName("http://example.org/wssample/echo/", "EchoService");
    QName portName = new QName("http://example.org/wssample/echo/", "EchoServicePort");
    
    /** Create a service and add at least one port to it. **/ 
    Service service = Service.create(serviceName);
    service.addPort(portName, SOAPBinding.SOAP11HTTP_BINDING, endpointUrl);
    
    /** Create a Dispatch instance from a service.**/ 
    Dispatch<SOAPMessage> dispatch = service.createDispatch(portName, 
    SOAPMessage.class, Service.Mode.MESSAGE);
    
    /** Create SOAPMessage request. **/
    // compose a request message
    MessageFactory mf = MessageFactory.newInstance(SOAPConstants.SOAP_1_1_PROTOCOL);
    
    // Create a message.  This example works with the SOAPPART.
    SOAPMessage request = mf.createMessage();
    SOAPPart part = request.getSOAPPart();
    
    // Obtain the SOAPEnvelope and header and body elements.
    SOAPEnvelope env = part.getEnvelope();
    SOAPHeader header = env.getHeader();
    SOAPBody body = env.getBody();
    
    // Construct the message payload.
    SOAPElement operation = body.addChildElement("invoke", "ns1",
    "http://com/ibm/was/wssample/echo/");
    SOAPElement value = operation.addChildElement("arg0");
    value.addTextNode("ping");
    request.saveChanges();
    
    /** Invoke the service endpoint. **/
    SOAPMessage response = dispatch.invoke(request);
    

    优势(不是真的):最终可以让它执行与上述相同的行为。

    缺点:复杂的编程。非标准配置(在WSDL之外)。需要避免硬编码设置。界面变化很脆弱。手动同步服务器和客户端之间的设置 - 很容易省略,非常难以调试。

答案:

回到(1)。从WSDL生成客户端存根。将它用作接口契约 - 它应该设计得很好而不会改变。

然后花时间省去解决实际问题...;);)