[译]CXF 架构

5月 31, 2015 |

原文地址:https://www.packtpub.com/books/content/cxf-architecture

下图显示了cxf整个的架构:
cxf-architecture-1

Bus

Bus是cxf架构的主心骨,cxf由一个基于spring的cxf.xml配置文件组成,在servlet初始化时通过SpringBusFactory加载。它为所有的endpoint定义了通用的上下文。它整合所有的运行时基础组件且提供了一个共用的应用程序上下文。SpringBusFactory扫描且加载classpath路径META-INF/cxf目录下相关的配置文件来相应的构建应用程序上下文。根据下面的文件构建应用程序上下文:

  • META-INF/cxf/cxf.xml
  • META-INF/cxf/cxf-extension.xml
  • META-INF/cxf/cxf-property-editors.xml

XML文件是CXF安装bundle的核心库的一部分。CXF在内部使用Spring作为它的配置。如下的XML片段展示cxf.xml中Bus定义
<bean id="cxf" class="org.apache.cxf.bus.CXFBusImpl" />
核心的Bus组建是CXFBusImpl。这个类充当web service endpoint的incoming和outgoing请求的拦截器。这些拦截器一旦定义,对上下文的所以endpoints都是可用的。cxf文件也定义了其他的基础设施组件,比如BindingFactoryManager,ConduitFactoryManager等。这些组件是Bus的扩展。可用通过Bus.getExtension方法访问这些组件。这些基础设施组件注册之后便于查找,更新service endpoint级的各种参数,比如service binding, 传输协议,conduit(管道)等。

CXF Bus架构可以被覆盖,但是覆盖默认bus的行为需要小心。由于Bus是加载CXF运行时的核心组件,许多共享的对象作为运行时的一部分而加载。当覆盖默认的Bus时需要确保这些对象也被加载。
你可以扩展默认Bus来包含你自定义的组件或者服务对象,比如factory manager。你也可以向Bus添加拦截器。定义在Bus级的拦截器对所有的endpoint都适用。如下代码展示如何创建一个自定义的Bus。
SpringBeanFactory.createBus("mycxf.xml")
SpringBeanFactory类用于创建Bus。你可以实现或者重写原始cxf.xml文件中定义的bean。为了让CXF加载mycxf.xml文件,需要让其在classpath或者你可以使用一个工厂方法来加载该文件。如下的代码演示使用Bus级的拦截器。

前面的bus定义添加了outgoing消息的日志拦截器。

Frontend

CXF提供frontend模型概念,让你使用不同的frontend API创建web services。这些API让你使用简单工厂bean和JAX-WS实现创建web 服务。这些API也能让你创建动态web service客户端。CXF支持的主要的frontend是JAX-WS。

JAX-WS

JAX-WS是开发,发布和消费web services的规范。JAX-WS简化web service开发。它定义基于java的API来减轻开发和部署web service。这个规范支持致力于web service互操作性的ws-basic profile 1.1。这意味着一个web service能被任何语言编写的客户端调用和消费。JAX-WS也定义了如JAXB和SAAJ等标准。CXF提供JAX-WS完整的支持。

JAXB提供便捷的映射XML schema到java POJO。JAXB屏蔽SOAP 消息的XML schema 格式消息到java代码转换。这样开发人员不用关心XML和SOAP的解析。JAXB规范定义java和XML schema的绑定。SAAJ提供了处理SOAP消息中XML附件标准。

JAX-WS提供将java 普通class 转换为web service的注解库,和从wsdl中定义的服务到实现服务的java类的映射,来加速web service开发。根据JAXB规范将wsdl中定义的任何复合的类型映射到java 类。

如前面讨论,存在两种开发web service方法:Code-first和契约优先。关于JAX-WS,你可以根据你项目的特性使用这两种方法中的任何一种。

对于编码优先方式,先开发java类和接口且注释接口为web service。当java实现已经完成且你希望暴露实现为服务时这个方式特别有用。

典型的过程为:创建一个定义操作的SEI(Service Endpoint Interface)和一个实现该SEI方法的类。web service消费者使用SEI调用服务功能。SEI直接对应wsdl:portType元素。SEI中的方法对应wsdl:operation元素。

JAX-WS使用注解来转换一个SEI或者java类为web service。在上面的例子当中,定义在接口上的@webservice注解表明该接口是一个web service接口,也可以叫做Service Endpoint Interface。

契约优先方式,从存在的wsdl契约开始,产生java类来实现该服务。优点是你能准确控制哪些要暴露为服务。数据类型保持一致,这样就可以轻易地转为java对象而不会有移植问题。

wsdl的很多元素可以直接映射到实现服务的java 类 。比如wsdl:portType元素直接映射到SEI,type元素使用JAXB映射为java类,wsdl:service元素映射为访问web service的java类

WSDL2Java工具用于从wsdl产生web service。它有不同的选项控制如何产生SEI和web service的实现类。如果wsdl包含自定义XML schema类型,也被转为了等价的java类。

Simple frontend

除了JAX-WS frontend,CXF也支持所谓的"simple frontend"。simple frontend提供简单组件或者java类,使用发射机制来构建和发布web services。由于我们没有使用任何注解所以简单。对于JAX-WS我们需要对java 类添加注解来标示它是一个web service,使用工具完成java对象和wsdl转换。简单的frontend 使用工厂组件来创建服务和客户端。simple frontend使用java 反射API。
以下代码演示使用simple frontend创建web service

Messaging and Interceptors

CXF架构一个重要的元素是拦截器组件。拦截器是拦截消息交换、消息在客户端和服务器之间传递的组件,在CXF中通过拦截器链来完成。拦截器链的概念是CXF运行时的核心功能。
拦截器作用于从web service接收和发送、在链中处理的消息。链中的每个拦截器都是可以配置的,用户能控制拦截器的执行。
cxf-architecture-2

框架核心就是拦截器接口。它定义了两个抽象方法,handleMessage和handleFault。每个方法使用Message作为参数。开发者实现handleMessage来处理消息,handleFault处理错误情况。链中的每个拦截器顺序地对消息执行处理,链向前移动。当错误发生时,链上的每个拦截器的handleFault方法被调用,链断开,或者叫做向后移动。[注:按照handleMessage执行链的反方向执行]
拦截器经常组织为阶段(Phase),提供相似功能的拦截器被组织为同一个阶段。每个阶段执行特定的消息处理。然后每个阶段被添加到拦截器链中。所以,链是有序的拦截器阶段列表。流入消息和流出消息都会创建拦截器链。典型地web service endpoint 会有以下三条拦截器链

  • Inbound messages chain
  • Outbound messages chain
  • Error messages chain

它们内置了许多拦截器,比如日志,安全等,开发者也可以创建自己的拦截器。

Service model

Service model如它的名字,建模你的服务。它是一个组件框架以wsdl相似模型表现一个服务。它提供创建不同wsdl元素的功能,比如操作,绑定,endpoints,schema等。下图显示组成服务模型的各种组件。

cxf-architecture-3

服务模型组件可用于创建服务。如你在上图看到的,服务模型的关键组件是聚合其他服务模块的serviceInfo。ServiceInfo由或多或少代表wsdl的以下组件组成:

  • InterfaceInfo
  • OperationInfo
  • MessageInfo
  • BindingInfo
  • EndpointInfo

WEB SERVICE通常由CXF提供的一种frontend创建。即可以从java 类构建也可以从wsdl构建。
CXF frontend内部使用服务模块创建WEB SERVICE。比如,使用简单frontend,能通过ServerFactoryBean,ClientProxyFactoryBean等工厂组件创建,发布,消费WEB SERVICE。这些工厂类内部使用CXF的服务模块。

Data binding

数据绑定是任何WEB SERVICE开发的关键。数据绑定意味着java对象和XML元素映射。众所周知,WEB SERVICE以XML格式交换数据。所以得有种方式将XML转换为java对象,反之亦然。数据绑定组件帮你执行这个映射。CXF支持两种类型数据绑定-JAXB和Aegis。JAXB是CXF默认的数据绑定组件。作为一个开发者,你可以通过一个配置文件或者API来指定默认的数据绑定组件。如果没有指定绑定组件,那么JAXB作为默认绑定组件。最新的CXF使用JAXB 2.1。JAXB使用注解定义java对象和XML文件映射。如下代码显示JAXB注解用法:

上面的例子中,@Xml相关的注解代表JAXB用于java类到XML schema映射的JAXB元数据。比如,@XmlType注解表示OrderProcess类将映射为processOrder 复合xsd元素类型,这个复合类型含有名为arg0的Order类型的元素。
CXF也支持使用Aegis数据绑定组件进行java对象和XML映射。Aegis允许开发者通过它灵活的映射系统获得更好的控制。不需要依赖注解来指定映射关系。你的java代码是简洁的POJO。
Aegis也支持某些注解来指导绑定,Aegis支持的一些注解如下:

  • XmlAttribute
  • XmlElement
  • XmlParamType
  • XmlReturnType
  • XmlType

Aegis使用一个名为<MyJavaObject>.aegis.xml的文件定义映射,MyJavaObject是你要映射为XML的对象。Aegis读这个XML来执行需要的绑定。Aegis同样使用反射来完成java对象和XML的映射。如下是Aegis映射文件的样例:

以上的XML片段表示HelloWorld的sayHi方法的字符串参数映射为greeting。你可以通过如下的配置让WEB SERVICE使用Aegis进行数据绑定。

Protocol binding

Protocal binding将web service的消息和一个具体的协议格式绑定。 Web SERVICE术语中的消息,是一个带有输入输出参数的操作。Web SERVICE中定义的消息是逻辑消息。Endpoint使用的逻辑消息需要映射到物理数据格式。协议绑定规定了逻辑消息如何映射到网络传输中的实际的负载。
绑定和wsdl的port type类型直接相关。Port type定义抽象的操作和输入输出参数。它们定义逻辑的消息,然而绑定转换这个逻辑消息为底层协议的实际负载。以下的wsdl 部分是绑定详情示例:

如你在以上的绑定示例片段中看到的,使用<binding>元素绑定。这个元素有两个属性。Name和type。Name属性唯一标示这个绑定,type属性映射该binding到port type。Binding的name属性用于和endpoint关联。子元素定义实际的消息映射。在前面的例子中,通信协议使用SOAP 1.1。

CXF支持如下的绑定协议:

  • SOAP 1.1
  • SOAP 1.2
  • CORBA
  • Pure XML

Transports

Transport 定义在网络上传输消息高级的路由协议。传输协议和endpoint关联。一个endpoint可以和另一个endpoint使用特定的传输协议通信。传输的细节其实就是网络的细节。服务endpoint是SERVICE接口的物理呈现。Endpoint由网络细节和绑定组成。在wsdl中,传输细节是port元素的一部分。Port元素是SERVICE元素的一部分。以下是wsdl关于传输细节的示例:

如你在上面的XML片段看到的,service元素中指定了传输详情。Service元素的port子元素。Port元素的binding属性定义传输的详情。以上的例子显示绑定协议是soap、传输协议是http。
CXF的endpoint支持如下的传输协议:

  • HTTP
  • CORBA
  • JMS
  • Local

总结

在本文中我们描述了CXF架构,它构建在核心组件之上。这些组件为构建web service 提供基石。

Posted in: cxf | Tags:

Comments are closed.