cxf 消息寻址

简介: 一、消息寻址   WS-Addressing是将消息路由数据包含在SOAP头中的一种标准方法。利用WS-Addressing的消息可以在标准化的SOAP头中包含自己的包含发送元数据,而不是依赖于网络层传输来传送路由信息。

一、消息寻址

  WS-Addressing是将消息路由数据包含在SOAP头中的一种标准方法。利用WS-Addressing的消息可以在标准化的SOAP头中包含自己的包含发送元数据,而不是依赖于网络层传输来传送路由信息。通过在标准的SOAP头中(wsa:ReplyTo)指定应答消息应该发送到哪里的端点引用,WS-Addressing可以支持异步交互方式。 服务提供者使用另一个连接,将应答消息发送给wsa:ReplyTo所指定的端点。这就将SOAP请求/应答消息的交互与HTTP请求/应答协议分离,这样,跨越任意时间的长时间运行的交互成为可能。

   通过这种方式,当服务器端需要较长时间来处理业务的时候,不需要一直保持与客户端的连接,当处理完毕之后,服务器将结果返回给指定的客户端。这类似于异步的交互。 

二、基于cxf的实现

  编写wsdl文件,存放于工程的src目录下

<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions xmlns="http://schemas.xmlsoap.org/wsdl/"
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://apache.org/hello_world_soap_http"
    xmlns:x1="http://apache.org/hello_world_soap_http/types" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="HelloWorld"
    targetNamespace="http://apache.org/hello_world_soap_http">
    <wsdl:types>
        <schema xmlns="http://www.w3.org/2001/XMLSchema"
            targetNamespace="http://apache.org/hello_world_soap_http/types"
            elementFormDefault="qualified">
            <element name="sayHi">
                <complexType />
            </element>
            <element name="sayHiResponse">
                <complexType>
                    <sequence>
                        <element name="responseType" type="xsd:string" />
                    </sequence>
                </complexType>
            </element>
            <element name="greetMe">
                <complexType>
                    <sequence>
                        <element name="requestType" type="xsd:string" />
                    </sequence>
                </complexType>
            </element>
            <element name="greetMeResponse">
                <complexType>
                    <sequence>
                        <element name="responseType" type="xsd:string" />
                    </sequence>
                </complexType>
            </element>
            <element name="greetMeOneWay">
                <complexType>
                    <sequence>
                        <element name="requestType" type="xsd:string" />
                    </sequence>
                </complexType>
            </element>
            <element name="pingMe">
                <complexType />
            </element>
            <element name="pingMeResponse">
                <complexType />
            </element>
            <element name="faultDetail">
                <complexType>
                    <sequence>
                        <element name="minor" type="xsd:short" />
                        <element name="major" type="xsd:short" />
                    </sequence>
                </complexType>
            </element>
        </schema>
    </wsdl:types>
    <wsdl:message name="sayHiRequest">
        <wsdl:part element="x1:sayHi" name="in" />
    </wsdl:message>
    <wsdl:message name="sayHiResponse">
        <wsdl:part element="x1:sayHiResponse" name="out" />
    </wsdl:message>
    <wsdl:message name="greetMeRequest">
        <wsdl:part element="x1:greetMe" name="in" />
    </wsdl:message>
    <wsdl:message name="greetMeResponse">
        <wsdl:part element="x1:greetMeResponse" name="out" />
    </wsdl:message>
    <wsdl:message name="greetMeOneWayRequest">
        <wsdl:part element="x1:greetMeOneWay" name="in" />
    </wsdl:message>
    <wsdl:message name="pingMeRequest">
        <wsdl:part name="in" element="x1:pingMe" />
    </wsdl:message>
    <wsdl:message name="pingMeResponse">
        <wsdl:part name="out" element="x1:pingMeResponse" />
    </wsdl:message>
    <wsdl:message name="pingMeFault">
        <wsdl:part name="faultDetail" element="x1:faultDetail" />
    </wsdl:message>
    <wsdl:portType name="Greeter">
        <wsdl:operation name="sayHi">
            <wsdl:input message="tns:sayHiRequest" name="sayHiRequest" />
            <wsdl:output message="tns:sayHiResponse" name="sayHiResponse" />
        </wsdl:operation>
        <wsdl:operation name="greetMe">
            <wsdl:input message="tns:greetMeRequest" name="greetMeRequest" />
            <wsdl:output message="tns:greetMeResponse" name="greetMeResponse" />
        </wsdl:operation>
        <wsdl:operation name="greetMeOneWay">
            <wsdl:input message="tns:greetMeOneWayRequest" name="greetMeOneWayRequest" />
        </wsdl:operation>
        <wsdl:operation name="pingMe">
            <wsdl:input name="pingMeRequest" message="tns:pingMeRequest" />
            <wsdl:output name="pingMeResponse" message="tns:pingMeResponse" />
            <wsdl:fault name="pingMeFault" message="tns:pingMeFault" />
        </wsdl:operation>
    </wsdl:portType>
    <wsdl:binding name="Greeter_SOAPBinding" type="tns:Greeter">
        <soap:binding style="document"
            transport="http://schemas.xmlsoap.org/soap/http" />
        <wsdl:operation name="sayHi">
            <soap:operation soapAction="" style="document" />
            <wsdl:input name="sayHiRequest">
                <soap:body use="literal" />
            </wsdl:input>
            <wsdl:output name="sayHiResponse">
                <soap:body use="literal" />
            </wsdl:output>
        </wsdl:operation>
        <wsdl:operation name="greetMe">
            <soap:operation soapAction="" style="document" />
            <wsdl:input name="greetMeRequest">
                <soap:body use="literal" />
            </wsdl:input>
            <wsdl:output name="greetMeResponse">
                <soap:body use="literal" />
            </wsdl:output>
        </wsdl:operation>
        <wsdl:operation name="greetMeOneWay">
            <soap:operation soapAction="" style="document" />
            <wsdl:input name="greetMeOneWayRequest">
                <soap:body use="literal" />
            </wsdl:input>
        </wsdl:operation>
        <wsdl:operation name="pingMe">
            <soap:operation style="document" />
            <wsdl:input>
                <soap:body use="literal" />
            </wsdl:input>
            <wsdl:output>
                <soap:body use="literal" />
            </wsdl:output>
            <wsdl:fault name="pingMeFault">
                <soap:fault name="pingMeFault" use="literal" />
            </wsdl:fault>
        </wsdl:operation>
    </wsdl:binding>


    <!-- SOAPService 的访问地址, 与server中的发布地址一致 -->
    <wsdl:service name="SOAPService">
        <wsdl:port binding="tns:Greeter_SOAPBinding" name="SoapPort">
            <soap:address location="http://localhost:9000/SoapContext/SoapPort" />
            <wswa:UsingAddressing xmlns:wswa="http://www.w3.org/2005/02/addressing/wsdl" />
        </wsdl:port>
    </wsdl:service>


</wsdl:definitions>

  服务实现类GreeterImpl:

package demo.ws_addressing.server;

import java.util.logging.Logger;

import javax.jws.WebService;

import org.apache.hello_world_soap_http.Greeter;
import org.apache.hello_world_soap_http.PingMeFault;
import org.apache.hello_world_soap_http.types.FaultDetail;

@WebService(name = "SoapPort", portName = "SoapPort", serviceName = "SOAPService", targetNamespace = "http://apache.org/hello_world_soap_http", wsdlLocation = "file:./src/hello_world_addr.wsdl")
// wsdlLocation 指定wsdl文件的地址
public class GreeterImpl implements Greeter {

    private static final Logger LOG = Logger.getLogger(GreeterImpl.class
            .getPackage().getName());

    public String greetMe(String me) {
        LOG.info("Executing operation greetMe");
        System.out.println("Executing operation greetMe");
        System.out.println("Message received: " + me + "\n");
        return "Hello " + me;
    }

    public void greetMeOneWay(String me) {
        LOG.info("Executing operation greetMeOneWay");
        System.out.println("Executing operation greetMeOneWay\n");
        System.out.println("Hello there " + me);
    }

    public String sayHi() {
        LOG.info("Executing operation sayHi");
        System.out.println("Executing operation sayHi\n");
        return "Bonjour";
    }

    public void pingMe() throws PingMeFault {
        FaultDetail faultDetail = new FaultDetail();
        faultDetail.setMajor((short) 2);
        faultDetail.setMinor((short) 1);
        LOG.info("Executing operation pingMe, throwing PingMeFault exception");
        System.out
                .println("Executing operation pingMe, throwing PingMeFault exception\n");
        throw new PingMeFault("PingMeFault raised by server", faultDetail);
    }

}

  服务器端配置文件server.xml,存放在demo.ws_addressing.server包下

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:cxf="http://cxf.apache.org/core" xmlns:wsa="http://cxf.apache.org/ws/addressing"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation=" http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <cxf:bus>
        <cxf:features>
            <wsa:addressing />
        </cxf:features>
    </cxf:bus>
</beans>

  服务端启动类Server:

package demo.ws_addressing.server;

import java.net.URL;
import javax.xml.ws.Endpoint;

import org.apache.cxf.Bus;
import org.apache.cxf.BusFactory;
import org.apache.cxf.bus.spring.SpringBusFactory;

public class Server {

    protected Server() throws Exception {
        System.out.println("Starting Server");

        SpringBusFactory bf = new SpringBusFactory();
        URL busFile = Server.class.getResource("server.xml");
        Bus bus = bf.createBus(busFile.toString());
        BusFactory.setDefaultBus(bus);

        Object implementor = new GreeterImpl();
        String address = "http://localhost:9000/SoapContext/SoapPort"; // 发布服务地址,与wsdl中的访问地址一致
        Endpoint.publish(address, implementor);
    }

    public static void main(String args[]) throws Exception {
        new Server();
        System.out.println("Server ready...");

        Thread.sleep(5 * 60 * 1000);
        System.out.println("Server exiting");
        System.exit(0);
    }
}

  客户端配置文件client.xml存放在demo.ws_addressing.client包下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cxf="http://cxf.apache.org/core"
    xmlns:wsa="http://cxf.apache.org/ws/addressing" xmlns:http="http://cxf.apache.org/transports/http/configuration"
    xsi:schemaLocation="http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd 
        http://cxf.apache.org/transports/http/configuration http://cxf.apache.org/schemas/configuration/http-conf.xsd 
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
<!--     表示服务器端处理完成后,将结果返回给"http://localhost:9990/decoupled_endpoint"。 这个地址。如果直接返回给自己,则可将下面注释 -->
    <http:conduit
        name="{http://apache.org/hello_world_soap_http}SoapPort.http-conduit">
        <http:client DecoupledEndpoint="http://localhost:9990/decoupled_endpoint" />
    </http:conduit>
    
    <cxf:bus>
        <cxf:features>
            <wsa:addressing />
        </cxf:features>
    </cxf:bus>
</beans>

  客户端访问类Client:

package demo.ws_addressing.client;

import static org.apache.cxf.ws.addressing.JAXWSAConstants.CLIENT_ADDRESSING_PROPERTIES;

import java.lang.reflect.UndeclaredThrowableException;
import java.net.URL;
import java.util.Map;

import javax.xml.namespace.QName;
import javax.xml.ws.BindingProvider;

import org.apache.cxf.Bus;
import org.apache.cxf.BusFactory;
import org.apache.cxf.bus.spring.SpringBusFactory;
import org.apache.cxf.ws.addressing.AddressingProperties;
import org.apache.cxf.ws.addressing.AttributedURIType;
import org.apache.cxf.ws.addressing.ObjectFactory;
import org.apache.hello_world_soap_http.Greeter;
import org.apache.hello_world_soap_http.PingMeFault;
import org.apache.hello_world_soap_http.SOAPService;

public final class Client {

    private static final QName SERVICE_NAME = new QName(
            "http://apache.org/hello_world_soap_http", "SOAPService");
    private static final ObjectFactory WSA_OBJECT_FACTORY = new ObjectFactory();
    private static final String USER_NAME = System.getProperty("user.name");

    private Client() {
    }

    public static void main(String args[]) throws Exception {
 
        try {
            URL wsdlURL = Client.class.getClassLoader().getResource(
                    "hello_world_addr.wsdl");//加载wsdl文件

            SpringBusFactory bf = new SpringBusFactory();
            URL busFile = Client.class.getResource("client.xml");
            Bus bus = bf.createBus(busFile.toString());
            BusFactory.setDefaultBus(bus);

            SOAPService service = new SOAPService(wsdlURL, SERVICE_NAME);
            Greeter port = service.getSoapPort();

            implicitPropagation(port);

            // explicitPropagation(port);

            // implicitPropagation(port);

        } catch (UndeclaredThrowableException ex) {
            ex.getUndeclaredThrowable().printStackTrace();
        } catch (Throwable ex) {
            ex.printStackTrace();
        } finally {
            System.exit(0);
        }
    }

    /**
     * A series of invocations with implicitly propogated Message Addressing
     * Properties.
     */
    private static void implicitPropagation(Greeter port) {
        System.out.println();
        System.out.println("Implicit MessageAddressingProperties propagation");
        System.out.println("------------------------------------------------");

        System.out.println("Invoking sayHi...");
        String resp = port.sayHi();
        System.out.println("Server responded with: " + resp + "\n");

        System.out.println("Invoking greetMe...");
        resp = port.greetMe(USER_NAME);
        System.out.println("Server responded with: " + resp + "\n");

        System.out.println("Invoking greetMeOneWay...");
        port.greetMeOneWay(USER_NAME);
        System.out.println("No response from server as method is OneWay\n");

        try {
            System.out.println("Invoking pingMe, expecting exception...");
            port.pingMe();
        } catch (PingMeFault ex) {
            System.out.println("Expected exception occurred: " + ex);
        }
    }

    private static AddressingProperties createMaps() {
        // get Message Addressing Properties instance
        AddressingProperties maps = new AddressingProperties();

        // set MessageID property
        AttributedURIType messageID = WSA_OBJECT_FACTORY
                .createAttributedURIType();
        messageID.setValue("urn:uuid:" + System.currentTimeMillis());
        maps.setMessageID(messageID);
        return maps;
    }

    /**
     * A series of invocations with explicitly propogated Message Addressing
     * Properties.
     */
    private static void explicitPropagation(Greeter port) {
        System.out.println();
        System.out.println("Explicit MessageAddressingProperties propagation");
        System.out.println("------------------------------------------------");

        // associate MAPs with request context
        Map<String, Object> requestContext = ((BindingProvider) port)
                .getRequestContext();
        requestContext.put(CLIENT_ADDRESSING_PROPERTIES, createMaps());

        System.out.println("Invoking sayHi...");
        String resp = port.sayHi();
        System.out.println("Server responded with: " + resp + "\n");

        // set the RelatesTo property to the initial message ID, so that
        // the series of invocations are explicitly related
        // RelatesToType relatesTo = WSA_OBJECT_FACTORY.createRelatesToType();
        // relatesTo.setValue(messageID.getValue());
        // maps.setRelatesTo(relatesTo);

        System.out.println("Invoking greetMe...");
        requestContext.put(CLIENT_ADDRESSING_PROPERTIES, createMaps());
        resp = port.greetMe(USER_NAME);
        System.out.println("Server responded with: " + resp + "\n");

        System.out.println("Invoking greetMeOneWay...");
        requestContext.put(CLIENT_ADDRESSING_PROPERTIES, createMaps());
        port.greetMeOneWay(USER_NAME);
        System.out.println("No response from server as method is OneWay\n");

        // disassociate MAPs from request context
        requestContext.remove(CLIENT_ADDRESSING_PROPERTIES);
    }
}

  分别运行Server类和Client类即可正常访问。通过tcpMon监听结果如下:

  1、当client中没有指定<http:conduit>元素时:

    请求:

    响应

    请求被处理后,结果返回给了原来的地址。

  2、当client中指定了<http:conduit>元素时:    

    请求

    该soap请求<soap:Header>中指定了处理完成后,将结果返回给特定的地址。

    响应

    响应为202,没有响应体。服务器已接受请求,但尚未处理。正如它可能被拒绝一样,最终该请求可能会也可能不会被执行。服务器接收到请求后,将处理后的结果转发给"http://localhost:9990/decoupled_endpoint"  这个地址。

目录
相关文章
|
10月前
|
芯片
|
消息中间件 JavaScript Java
SpringBoot 实战 (十六) | 整合 WebSocket 基于 STOMP 协议实现广播消息
如题,今天介绍的是 SpringBoot 整合 WebSocket 实现广播消息。
SpringBoot 实战 (十六) | 整合 WebSocket 基于 STOMP 协议实现广播消息
|
Apache
详解 Apache SkyWalking 的跨进程传播协议
SkyWalking 跨进程传播协议是用于上下文的传播,本文介绍的版本是3.0,也被称为为sw8协议。
635 0
详解 Apache SkyWalking 的跨进程传播协议
|
网络协议 Java 开发工具
mPaaS 服务端核心组件:移动同步服务 MSS 架构解析
移动同步服务 MSS 是移动开发平台 mPaaS 的核心基础服务组件之一,源自于蚂蚁金服集团内面向移动应用从服务端到客户端进行海量数据推送的全链路解决方案。
2683 0
|
分布式计算 Spark
spark2.1.0之源码分析——RPC传输管道处理器详解
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/beliefer/article/details/81326016 提示:阅读本文前最好先阅读: 《Spark2.
1636 0
|
前端开发 Java 容器
SpringBoot-WebSocket广播消息+单点消息(指定用户发送消息)
SpringBoot-WebSocket广播消息+单点消息(指定用户发送消息) 前言 关于Springboot中WebSocket的介绍这里就不赘述了。
6123 0
|
Java 容器 应用服务中间件