`
reymont
  • 浏览: 529436 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

使用CXF Interceptor&Feature

    博客分类:
  • CXF
 
阅读更多

使用CXF Interceptor特性

 

本例代码在附件中

 

Web Service中,客户端和服务端通过交换信息来互相通信。信息在客户端组装,在服务端解组。在Web Service术语中,组装表示将JAVA对象转换为XML文件,这些XML文档将被传输到网络中;反而言之,解组就是将XML文档转换为JAVA对象。

 

当客户端向服务端发送请求,请求中的数据将被组装并传输到服务器。服务器获取该数据,解组,最后调用服务方法。当服务器发送响应给客户端时,将重复该过程。组装和解组是客户端和服务端提供的核心功能。CXF通过Interceptor来提供这些功能。

 

Interceptor通过监听传输过来的信息来提供核心功能。这些功能包括:组装、解组、操纵消息头、执行认证检查、验证消息数据等。CXF提供内置的Interceptor来实现这些功能。用户也可以自定义InterceptorInterceptorphases组织起来,以链的形式调用,

 

理解interceptor phase chain

 

Phase可以被当作分类框,将类似功能的Interceptor组织起来。

 

有两种Interceptor链,inbound链和outbound链。两种都有一系列的Phase。例如,在inbound链中有UNMARSHAL Phase,用来解组信息数据,并将其转化为JAVA对象。

 

对于每个请求来讲,在服务端创建inbound Interceptor;对于每个响应来讲,将创建outbound Interceptor

消息传输到链中,按特定的顺序在Phase中的Interceptor执行。

在信息传输到服务端之前,inbound Interceptor操作信息。

在信息传输到客户端之前,outbound Interceptor操作信息。

如果出现错误,Interceptor链释放自己,不去调用应用。

 

interceptor API概览

 

PhaseInterceptor继承自Interceptor接口。AbstractPhaseInterceptor实现了PhaseInterceptor

 

Interceptor接口

 

如果要自定义Interceptor,就必须直接或间接实现Interceptor接口。Interceptor接口定义了两个方法。handleMessagehandleFault

 

package org.apache.cxf.interceptor;

public interface Interceptor<T extends Message> {

   void handleMessage(T message) throws Fault;

   void handleFault(T message);

}

 

handleMessage方法需要org.apache.cxf.message.Message对象。这是执行信息的核心方法。为了自定义Interceptor就必须实习该方法,并提供执行信息的逻辑。

handleFault方法同样需要org.apache.cxf.message.Message对象。在执行Interceptor过程中出现错误时将会调用该方法。

 

PhaseInterceptor接口

 

大多数核心Interceptor都是实现继承自Interceptor接口的PhaseInterceptor

 

PhaseInterceptor定义了4个方法。

 

getAfter将返回一个Set,包含了在这个Interceptor之前执行InterceptorIDs

getBefore将返回一个Set,包含了在这个Interceptor之后执行InterceptorIDs

getId返回ID

getPhase返回这个Interceptor所在的phase

 

为了自定义Interceptor,开发者必须继承AbstractPhaseInterceptor抽象类。

 

AbstractPhaseInterceptor抽象类

 

AbstractPhaseInterceptor定义了构造器,可以为自定义的Interceptor指定特定的phase。当你指定了phase,自定义的Interceptor将会安排在链中PhaseAbstractPhaseInterceptor提供了空实现的handleFault。开发者可以覆盖这个方法。开发者必须实现handleMessage方法。

 

查看AbstractPhaseInterceptor抽象类,它已实现PhaseInterceptor接口的方法。Phase的顺序由PhaseInterceptorChain类决定

 

开发自定义的interceptor

 

为了演示interceptor的功能,假定一个用例:只有经过认证的用户才能调用Web Service,用户认证需要获取SOAP头的信息。

 

为了实现这些需求,创建两个interceptor,一个客户端,一个服务端。客户端interceptor负责拦截即将发出的SOAP信息,并在SOAP头中添加用户验证。服务端interceptor负责拦截收到的SOAP信息,从SOAP信息获取用户认证信息并验证该用户。如果用户验证失败,将抛出异常,在这种情况下阻止Web Service的运行。

 

开发自定义的interceptor分为如下几个步骤:

 

开发服务端的interceptor

Web Service服务类添加服务端interceptor

开发客户端interceptor

在客户端添加客户端interceptor

开发发布Web Service的服务器。

 

开发服务端interceptor

 

OrderProcessUserCredentialInterceptor继承自AbstractSoapInterceptorAbstractSoapInterceptor继承自AbstractPhaseInterceptorAbstractSoapInterceptor提供了获取SOAP头和版本的信息。

 

OrderProcessUserCredentialInterceptor默认构造函数中,指定了Phase.PRE_INVOKE,代表着该interceptor将先于Web Service服务类执行。

 

public OrderProcessUserCredentialInterceptor() {

        super(Phase.PRE_INVOKE);

    }

 

handleMessage方法中,SoapMessage提供了获取SOAP头的信息。使用message.getHeader获取SOAP头中<OrderCredentials>元素

 

Header header = message.getHeader(qnameCredentials);

 

<soap:Header>

      <OrderCredentials>

         <username>John</username>

         <password>password</password>

      </OrderCredentials>

</soap:Header>

 

OrderCredentials节点下,可以获得用户名和密码节点。

 

            Element elementOrderCredential = (Element) header.getObject();

            Node nodeUser = elementOrderCredential.getFirstChild();

            Node nodePassword = elementOrderCredential.getLastChild();

 

package demo.order.server;

import javax.xml.namespace.QName;

import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.binding.soap.interceptor.AbstractSoapInterceptor;
import org.apache.cxf.headers.Header;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.phase.Phase;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

public class OrderProcessUserCredentialInterceptor extends AbstractSoapInterceptor {

    private String userName;
    private String password;

    public OrderProcessUserCredentialInterceptor() {
        super(Phase.PRE_INVOKE);
    }

    public void handleMessage(SoapMessage message) throws Fault {

        System.out.println("OrderProcessUserCredentialInterceptor handleMessage invoked");
        QName qnameCredentials = new QName("OrderCredentials");

        // Get header based on QNAME
        if (message.hasHeader(qnameCredentials)) {
            Header header = message.getHeader(qnameCredentials);

            Element elementOrderCredential = (Element) header.getObject();
            Node nodeUser = elementOrderCredential.getFirstChild();
            Node nodePassword = elementOrderCredential.getLastChild();

            if (nodeUser != null) {
                userName = nodeUser.getTextContent();
            }
            if (nodePassword != null) {
                password = nodePassword.getTextContent();
            }
        }

        System.out.println("userName reterived from SOAP Header is " + userName);
        System.out.println("password reterived from SOAP Header is " + password);

        // Perform dummy validation for John
        if ("John".equalsIgnoreCase(userName) && "password".equalsIgnoreCase(password)) {
            System.out.println("Authentication successful for John");
        } else {
            throw new RuntimeException("Invalid user or password");
        }
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

 

 

 

 

 

Web Service业务类添加interceptor

 

Web Service业务类可以添加配置文件或者定义annotations添加interceptor

 

添加InInterceptors注释定义了一个Inbound interceptor,将在Web Service执行之前调用。

 

@org.apache.cxf.interceptor.InInterceptors (interceptors = {"demo.

order.server.OrderProcessUserCredentialInterceptor" })

 

 

 

 

package demo.order;

import javax.jws.WebService;

@org.apache.cxf.interceptor.InInterceptors(interceptors = {"demo.order.server.OrderProcessUserCredentialInterceptor"})
@WebService
public class OrderProcessImpl implements OrderProcess {

    public String processOrder(Order order) {
        System.out.println("Processing order...");
        String orderID = validate(order);
        return orderID;
    }

    /**
     * Validates the order and returns the order ID
	*
     */
    private String validate(Order order) {
        String custID = order.getCustomerID();
        String itemID = order.getItemID();
        int qty = order.getQty();
        double price = order.getPrice();

        if (custID != null && itemID != null && qty > 0 && price > 0.0) {
            return "ORD1234";
        }

        return null;
    }
}

 

 

 

 

开发客户端interceptor

 

同样的OrderProcessClientHandler继承自AbstractSoapInterceptor

 

OrderProcessClientHandler默认构造器,指定了super(Phase.WRITE),还addAfter方法。addAfter指定了OrderProcessClientHandler将在CXF内置SoapPreProtocolOutInterceptor之后添加。OrderProcessClientHandler将在Phase.WRITE并在SoapPreProtocolOutInterceptor之后运行。SoapPreProtocolOutInterceptor负责建立SOAP版本和头,因此任何SOAP头元素的操作都必须在SoapPreProtocolOutInterceptor之后执行。

 

public OrderProcessClientHandler() {

      super(Phase.WRITE);

      addAfter(SoapPreProtocolOutInterceptor.class.getName());

}

 

构造函数new Header(qnameCredentials, elementCredentials);创建了Header对象,并设置了OrderCredentials元素。最后message.getHeaders().add(header)SOAP头添加到信息中。

 

 

 

package demo.order.client;

import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.binding.soap.interceptor.AbstractSoapInterceptor;
import org.apache.cxf.binding.soap.interceptor.SoapPreProtocolOutInterceptor;
import org.apache.cxf.headers.Header;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.phase.Phase;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

public class OrderProcessClientHandler extends AbstractSoapInterceptor {

    public String userName;
    public String password;

    public OrderProcessClientHandler() {
        super(Phase.WRITE);
        addAfter(SoapPreProtocolOutInterceptor.class.getName());
    }

    public void handleMessage(SoapMessage message) throws Fault {

        System.out.println("OrderProcessClientHandler handleMessage invoked");

        DocumentBuilder builder = null;
        try {
            builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        }
        Document doc = builder.newDocument();
        Element elementCredentials = doc.createElement("OrderCredentials");
        Element elementUser = doc.createElement("username");
        elementUser.setTextContent(getUserName());
        Element elementPassword = doc.createElement("password");
        elementPassword.setTextContent(getPassword());
        elementCredentials.appendChild(elementUser);
        elementCredentials.appendChild(elementPassword);

        // Create Header object
        QName qnameCredentials = new QName("OrderCredentials");
        Header header = new Header(qnameCredentials, elementCredentials);
        message.getHeaders().add(header);
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }
}

 

 

客户端添加interceptor

 

OrderProcessClientHandler设置了usernamepassword。通过ClientProxy.getClient(client);获取Client对象,并通过cxfClient.getOutInterceptors().add(clientInterceptor)clientInterceptor作为outbound interceptor

 

package demo.order.client;

import demo.order.OrderProcess;
import demo.order.Order;

import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.transport.http.gzip.GZIPInInterceptor;
import org.apache.cxf.transport.http.gzip.GZIPOutInterceptor;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public final class Client {

    public Client() {
    }

    public static void main(String args[]) throws Exception {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"client-beans.xml"});

        OrderProcess client = (OrderProcess) context.getBean("orderClient");
//        OrderProcess client = (OrderProcess) context.getBean("orderClient2");
        OrderProcessClientHandler clientInterceptor = new OrderProcessClientHandler();
        clientInterceptor.setUserName("John");
        clientInterceptor.setPassword("password");
        org.apache.cxf.endpoint.Client cxfClient = ClientProxy.getClient(client);
        cxfClient.getOutInterceptors().add(clientInterceptor);

        Order order = new Order();
        order.setCustomerID("C001");
        order.setItemID("I001");
        order.setQty(100);
        order.setPrice(200.00);

        String orderID = client.processOrder(order);
        String message = (orderID == null) ? "Order not approved" : "Order approved; order ID is " + orderID;
        System.out.println(message);
    }
}

 

 

 

 

开发发布Web Service的服务器

 

 

 

package demo.order;

import org.apache.cxf.feature.LoggingFeature;
import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.interceptor.LoggingOutInterceptor;
import org.apache.cxf.jaxws.JaxWsServerFactoryBean;
import org.apache.cxf.transport.http.gzip.GZIPFeature;
import org.apache.cxf.transport.http.gzip.GZIPInInterceptor;
import org.apache.cxf.transport.http.gzip.GZIPOutInterceptor;

public class OrderProcessServerStart {

    public static void main(String[] args) throws Exception {

        OrderProcess orderProcess = new OrderProcessImpl();
        LoggingFeature log = new LoggingFeature();
        GZIPFeature gzip = new GZIPFeature();
        gzip.setThreshold(1);
        JaxWsServerFactoryBean server = new JaxWsServerFactoryBean();
        server.setServiceBean(orderProcess);
        server.setAddress("http://localhost:8080/OrderProcess");

        server.getFeatures().add(log);
        server.getFeatures().add(gzip);
        //server.getFeatures().add(log);
        //server.getInInterceptors().add(new LoggingInInterceptor());
        //server.getOutInterceptors().add(new LoggingOutInterceptor());


        server.create();
        System.out.println("Server ready....");



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

 

 

 

理解CXF features

 

Feature其实是interceptors另外一种形式。可以使用feature组件来代替直接使用interceptor

 

本例中添加了loggzip两个feature,正如Interceptor中所描述的phase的概念,添加loggzip的顺序会影响LoggingFeature显示的内容。

 

请读者自行尝试OrderProcessServerStart

 

        server.getFeatures().add(log);

        server.getFeatures().add(gzip);

        //server.getFeatures().add(log);

 

client-beans.xml

 

            <bean class="org.apache.cxf.feature.LoggingFeature"></bean>

            <bean class="org.apache.cxf.transport.http.gzip.GZIPFeature" >  

                <property name="threshold" value="1" />  

            </bean>

            <!--bean class="org.apache.cxf.feature.LoggingFeature"></bean-->

 

安排loggzip的添加次序。

 

LoggingFeature

 

LoggingFeature可以独立于服务端和客户端。也就是说,可以服务端添加LoggingFeature,而客户端不添加,反之亦然。

 

 

GZIPFeature

 

GZIPFeature不同于LoggingFeature,客户端和服务端必须同时实现GZIPFeature,不然会抛出异常javax.xml.ws.soap.SOAPFaultException: Couldn't parse stream.

 

查看添加GZIPFeature的服务器需要借助于工具。Tcpmon是其中的一个选择,另外LoggingFeature提供了tcpmon类似的功能。

 

client-beans.xml<http-conf:client>元素指定了AcceptEncoding属性,这个属性暗示客户端应用将会接受gzip的内容。

 

 

tcpmon

 

如何用Apache TCPMon来截获SOAP消息

 

http://www.blogjava.net/heyang/archive/2010/12/10/340294.html

 

下载地址http://ws.apache.org/commons/tcpmon/download.cgi

 

 

在执行CXF过程中,是无法查看到组装和解组的内容。如果希望看到内容,则需要借助工具。外部工具如tcpmon。将client-beans.xml address中的端口修改你希望的端口,如8081。然后在OrderProcessServerStart查看发布的端口

 

server.setAddress("http://localhost:8080/OrderProcess");

 

8080。在tcpmon解压的目录bin中执行tcpmon.bat,出现tcpmon界面。切换到Admin。在Listen Port #处填写8081,在Target Port #填写8080,点击Add。然后切换到Sender。为了方便查看XML,在左下角有个XML Format,将其勾选上,tcpmon会将捕获的内容整理为XML格式。执行Client,便可以再Sender界面查看到XML的具体内容了。

 

 

threshold

 

忽略1 byte并压缩剩下的内容。Threshold若为0值表示全部内容都将压缩。如果Threshold未提供任何值,那么默认将执行全部内容压缩。

 

 

分享到:
评论
3 楼 hl174 2016-01-06  
还是有点看不懂 存着再说
2 楼 Seven.Q 2015-02-27  
哎呦,不错哦!看源码,这篇文章倒是帮了不少忙
1 楼 lxiaoy605 2014-05-16  
谢谢,很注重实际运用,书上的看不懂!

相关推荐

    CXF&spring实例

    2. **服务端之spring配置**:在"CXF&spring初体验【服务端之spring配置文件】"中,我们会学习如何使用Spring的XML配置文件或Java配置来声明和管理CXF服务。这通常包括定义服务接口、实现类、以及服务的发布和地址...

    CXF拦截器(Interceptor)的使用

    标题:“CXF拦截器(Interceptor)的使用” 描述:“讲解了cxf实现拦截器的原因、核心API及使用方法” 在深入探讨CXF拦截器的使用之前,我们首先需要理解其在CXF框架中的核心作用与价值。Apache CXF是一个开源框架,...

    使用CXF和camel-cxf调用webservice

    本篇文章将详细介绍如何使用CXF和camel-cxf调用Web服务,以及这两个工具的核心功能和使用场景。 Apache CXF是一个全面的服务开发框架,它支持多种Web服务标准,如SOAP、WS-*协议栈、RESTful服务等。CXF提供了丰富的...

    WebService技术手册 CXF&XFire

    **WebService技术概述** WebService是一种基于...通过以上内容,你可以全面了解并掌握WebService的基础知识,以及CXF和XFire这两个关键框架的使用。学习并熟练运用这些技术,将有助于你构建高效、可靠的分布式系统。

    CXF使用EndpointImpl发布WebService加入拦截器

    在Java世界中,Apache CXF是一个广泛使用的开源框架,它允许开发者创建和消费Web服务。在Web服务开发中,拦截器扮演着至关重要的角色,它们提供了在消息发送和接收过程中插入自定义逻辑的能力。本篇文章将深入探讨...

    CXF Web Service & client

    - **JAX-WS(Java API for XML Web Services)**:CXF支持JAX-WS规范,允许开发者使用Java注解来声明服务接口和消息处理方法。 - **CXF的Endpoint和Server**:在CXF中,Endpoint是实际对外提供服务的对象,而Server...

    使用CXF开发RESTFul服务

    【标题】"使用CXF开发RESTFul服务"涉及到的核心技术是Apache CXF框架和RESTful API设计。Apache CXF是一个开源的Java框架,主要用于构建和消费Web服务,包括SOAP和RESTful服务。REST(Representational State ...

    使用CXF开发WebService简单实例

    本篇文章将深入探讨如何使用CXF来开发一个简单的“HelloWorld”Web服务实例。 首先,我们需要了解CXF的基本概念。CXF全称为CXF CXF (CXF on XFire),它整合了XFire和 Celtix两个项目,为开发者提供了一种灵活的方式...

    CXF发布WebService加入拦截器

    在Java世界中,Apache CXF是一个广泛使用的开源框架,它允许开发者创建和消费Web服务。当我们谈论"CXF发布WebService加入拦截器"时,这涉及到在CXF服务端和客户端增加拦截器来增强服务功能和控制流程。拦截器是CXF...

    CXF视频:1、使用CXF实现简单的HelloWorld

    【标题】"CXF视频:1、使用CXF实现简单的HelloWorld",这是一段关于Apache CXF框架的初级教程,旨在引导初学者通过实际操作理解如何利用CXF创建一个基本的“HelloWorld”服务。Apache CXF是一个开源的Java框架,它...

    使用CXF实现带header的soap服务

    4. **处理HTTP头信息**:CXF提供了拦截器(Interceptor)机制,可以通过自定义拦截器来读取和操作HTTP头。在`frontend/client`或`frontend/server`的拦截器链中添加自定义拦截器,拦截器可以访问并处理Message对象中...

    使用CXF: Java 2 WSDL

    【标题】:“使用CXF:Java 2 WSDL” 【描述】:在Java开发中,Apache CXF是一个广泛使用的开源框架,它允许开发者构建和部署Web服务。"Java 2 WSDL"指的是从Java类生成WSDL(Web Services Description Language)...

    webservice使用cxf的实例

    【标题】:“Web服务使用CXF的实例” 在IT行业中,Web服务是一种通过网络进行通信的标准接口,使得不同系统能够相互通信并交换数据。CXF(Code First eXtensible Framework)是Apache软件基金会的一个开源项目,它...

    CXF2.6.4配java1.6版完整包和使用说明

    这个"CXF2.6.4配java1.6版完整包和使用说明"是一个针对Java 1.6版本优化的CXF 2.6.4发行包,包含了所有必要的组件和文档,让你能够顺利地在Java 1.6环境下使用CXF进行服务开发。 CXF的核心功能包括: 1. **SOAP和...

    cxf+spring使用经验

    【cxf+spring 使用经验】 Apache CXF 是一个开源的 Web 服务框架,它整合了 Celtix 和 XFire 两大项目的优势,提供了全面的 JAX-WS 支持,允许开发者通过 Code First 或 WSDL First 的方式来创建和消费 Web 服务。...

    WebService_CXF实现及ANT

    在这个主题中,我们将深入探讨CXF的Interceptor拦截器、处理复杂类型对象的传递以及如何结合Spring进行集成,最后我们将学习如何使用ANT工具快速构建和部署CXF工程。 1. CXF Interceptor拦截器: 拦截器是CXF框架...

    02.CXF功能概述_CXF发展历史和使用CXF开发WebService服务器端

    【标题】"02.CXF功能概述_CXF发展历史和使用CXF开发WebService服务器端"主要探讨了Apache CXF框架在Web服务领域的应用及其发展历程,同时也涵盖了如何利用CXF来构建一个高效的WebService服务器端。 Apache CXF是一...

    使用CXF发布WebService

    当我们谈论“使用CXF发布WebService”时,我们实际上是在讨论如何利用Apache CXF框架创建和部署Web服务。Apache CXF是一个开源的Java框架,专门用于构建和消费Web服务,支持多种协议,如SOAP和RESTful。 首先,我们...

    java的webService源码(使用cxf)

    【Java WebService 源码使用 CXF 框架详解】 Java WebService 是一种基于标准的、平台无关的通信方式,它允许不同系统间的应用程序通过网络交换数据。CXF 是一个开源的 Java 库,它提供了创建和消费 WebService 的...

Global site tag (gtag.js) - Google Analytics