Apache CXF 架构简介

整个CXF架构主要由以下几个部分组成:
 
    1. BUS:包含 扩展(extensions)、拦截器和属性配置的注册入口 
    2. Front-end: Front-end 提供编程模型来创建服务 
    3. Messaging & Interceptors : 提供底层级别的消息和管道处理,大部分功能都建立在这个基础之上。 
    4. Pluggable Data Bindings: 插件式的数据绑定 
    5. Protocol Bindings: 解析协议的功能。 
    6. Transports: TransportFactory 创建Destinations(接受数据)和Conduits(发送数据)。 

下图各层顺序,可见他们是如何在一起工作的。




一、 BUS

Bus,作为CXF的核心,是运行时各种共享资源的提供者。共享资源包括像WSDL管理器,绑定工厂管理器等。Bus可以非常容易的扩展,以此来加入你自己的资源和服务,甚至用你自己的组件(tomcat)替换像HTTP destination factory(建立在Jetty基础之上)的默认的资源。

这种可扩展性使得依赖注入变得可能。默认的Bus实现建立在spring framework之上,通过依赖注入,在运行时,组装这些组件在一起供你使用。Bus的创建由BusFactory负责,默认是 SpringBusFactory,对应于默认Bus实现。

在构造过程中,SpringBusFactory 在classpath/META-INF/cxf(就包含在 CXF的Jar中)目录下搜索所有的bean配置文件, 并以此建立ApplicationContext。开发者也可提供自己的配置文件来定制Bus。以下文件默认会被扫描:
META-INF/cxf/cxf.xml (e.g., in cxf-rt-core only)
META-INF/cxf/cxf-extension.xml (e.g. in cxf-rt-bindings-soap)
META-INF/cxf/cxf-property-editors.xml (e.g. in cxf-rt-transports-http)

二、服务调用时如何处理的

客户端:





服务端:





三、 Front-end

Front-end 提供编程的方式来与CXF进行交互。提供的基础功能有:JAX-WS, JAX-RS, Simple和Javascript。各种基础功能相互独立,和绑定,核心功能类似。Front-end通过将拦截器加入到服务和端点来提供功能。

四、 Messaging & Interceptors

CXF建立在通用消息层之上,由Messages,Interceptors(拦截器),和InterceptorChains(拦截器链)组成。 Interceptors是功能单元的基础。通过分离消息处理和消息发送,使得CXF具备非常灵活的架构。可以对任何处理点进行配置。这也使得CXF局部 暂停&恢复拦截器链。

通过拦截器,开发者可以方便地在消息传递、处理的整个过程中对CXF进行扩展。拦截器的方法主要有两个:handleMessage和handleFault,分别对应消息处理和错误处理。在开发拦截器的时候需要注意两点:

1,拦截器不是线程安全的,不建议在拦截器中定义实例变量并使用它。
2,不要调用下一个拦截器的handleMessage或handleFault,这个工作由InterceptorChain来完成。

Interceptors定义了handleMessage方法,可以用来处理Message.这邪恶Interceptors可以组成一个链状的拦截器,即拦截器链。下面的例子说明了这个结构:

a. Header Interceptor只处理SOAP消息的header。
b. WS-Security Interceptor 用来解密和认证接受到的消息。
c. 发送数据的Interceptor用来序列化处理结果。

注意:Interceptors 是没有方向性的,本质上,他们都可以处理request,response,和fault。(关键是看你把这个拦截器放在哪里)

五、 Phase Interceptors

CXF提供了一个InterceptorChain的实现:PhaseInterceptorChain。当Interceptors加入到这个链时,他 们将按处理阶段进行排序分组。因此PhaseInterceptor需要告知链,它处于哪个阶段(即需要调用 super(Phase.PRE_PROTOCOL))。

我们假设一个简单的例子(注意,这些拦截器链在CXF中不是必须的,只是提供拦截点)。我们正在处理一个SOAP消息。有两个地方需要处理。第一、分发拦 截器组(Dispatch Interceptor) 负责解析SOAP的头部信息并决定将消息路由到哪个服务上。第二、反序列化拦截器组负责将SOAP body 绑定到 JAXB 对象上。分发拦截器组需要通过两个拦截器来实现,第一个ReadHeadersInterceptor,用来解析header信息,第二个拦截器WS- AddressingInInterceptor负责根据头部信息判断调用哪个服务。反序列化拦截器组只需要一个 JAXBUnmarshallerIntercptor。 ReadHeadersInterceptor 和 AddressingInInterceptor 的getPhase()返回"dispath"告诉 PhaseInterceptorChain 他们在Dispath 阶段.另外,ReadHeadersInterceptor 提供getBefore()方法,用来指定它必须在AddressingInInterceptor之前执行。

拦截链灵活可变。在以上例子上,我们可以把拦截器加到服务处理完成后,或者可以暂停拦截器链以便等待外部处理,像异步返回response。

六、 Fault Handling

在处理的任何阶段,拦截器都可能抛出Fault或者它的子类。这会导致停止正常处理,并调用善后机制:按顺序调用 handleFault 。

拦截器链具备失败观察者的功能。一旦失败,fault Interceptor被调用。fault observer将会触发一个新的链来处理错误。

七、 Exchanges

除了消息的概念外,还有个Exchage的概念。Exchange类保持当前入的消息,出的消息和错误消息的引用。还保持着Exchange自身的配置属性。Exchange的实例保持着当前调用的服务。

八、 Reentrant InterceptorChains(可重入的拦截器链)

PhaseInterceptorChain的一个非常有趣的特征是它自己是可重入的。这是一个强大的功能也有一点点危险。这个特征仅仅在CXF发送消息时使用。SoapOutInterceptor是最好的例子


public void handleMessage(Message m) {
writeSoapEnvelopeStart();
writeSoapBodyStart();

// invoke next interceptor, which writes the contents of the SOAP Body
m.getInterceptorChain().doIntercept(m);
writeSoapBodyEnd();

writeSoapEnvelopeEnd();


九、The Service Model(服务模型)

服务模型是CXF对服务的描述。由两部分组成。第一,有一个ServiceInfo类,包含一个类似WSDL描述服务和他的 operations,bindings,endpoints和schema。第二,有一个Service类,其中包含 ServiceInfo,data-binding(稍后介绍Data-binding) 信息,服务拦截器,服务属性等。

一个服务可以根据许多不同的资源来构建,包括classes和WSDL(1.1和2.0). 一般front-ends都通过Service Factory来创建服务。front-end通过Factory组件(ServerFactoryBean, ClientProxyFactoryBean)来创建,发布和消费服务。factory组件构建Service model,配置Interceptor,data bindings等。

Service model自身包被包含在ServiceInfo中。如下图所示:





十、 Data Bindings

Data Bindings 实现 XML elements和 Java 对象之间的映射关系。Data Bindings 在data和xml之间互相转换,产生XML schema,提供wsdl2java代码生成支持。并非所有的Data binding都支持这些功能。但最少,每个Data binding必须提供数据转换(对象和xml之间的转换啦)。更详细的说明,可以参考 http://cxf.apache.org/docs/data-binding-architecture.html。当前CXF支持的Data binding包括JAXB 2.x (default), Aegis, Apache XMLBeans, Service Data Objects (SDO) and JiBX (under development).

十一、Protocol Bindings

Protocal Bindings提供方法在传输层上映射具体的格式和协议。一个Protocal Bindings 包括两个主要部分:BindingFactory 和 Binding。BindingFactory负责从ServiceInfo创建Binding。Protocal Binding包含一个特殊的Inteceptor并实现了createMessage() 方法。这个方法负责创建符合Binding要求的消息。

目前,CXF支持的Protocal 包括:SOAP 1.1, SOAP 1.2, REST/HTTP, pure XML 和 CORBA.

a. The Soap Binding
CXF原生支持的是soap。它拥有自己的一个消息类SoapMessage。它增加了表示当前soapVesion以及header的字段。

Soap Binding还增加了一个特别的Interceptor,即SoapInterceptor。这个拦截器增加了两个方法:
Set getRoles();
Set getUnderstoodHeaders();

这就使得特定的SoapInterceptor能够理解特定的角色和header。

CXF也设计了其他的拦截器来处理Soap消息。
StaxInInterceptor: 根据传入的InputStream创建XMLStreamReader
ReadHeadersInterceptor: 从SoapMessage中读取消息头header
MustUnderstandInterceptor: 检查所有的MustUnderstand attributes是否符合所有SoapInterceptor的getUnderstoodHeaders()返回值。
SoapOutInterceptor:在发送soap消息前,处理消息。

b.其他Bingding。
其他bindings 包括 REST/HTTP binding, pure XML binding, 和 CORBA binding.

十二、Transports

CXF提供了一个自己的传输抽象层,对protocal binding和front-end隐藏具体的传输细节。当前支持的 transports 包括:HTTP, HTTPs, HTTP-Jetty, HTTP-OSGI,Servlet, local, JMS和 In-VM。 通过Camel transport,还可以支持SMTP/POP3, TCP和Jabber。

十三、Conduits(翻译是管道)

Conduit提供了发送消息的基础。一个Conduit是用ConduitInitiator创建的。发送一个消息有多个步骤:
1. 调用conduit.prepare(message):调用后就开始发送消息了,这个时候,Conduit会初始化一个连接,并为将发送的消息设置一个OutputStream(流)。
2. 将消息写入这个流。
3. 调用conduit.close(message): 关闭和释放所有相关的资源。

消息发送器还可以注册一个观察者 MessageObserver。如果这个Conduit是同步的,当消息被(客户端)接受到时,MessageObserver将可以得到通知。

十四、Destinations

Destinations是接受进来的消息的基础。DestinationFactory可以创建Destinations。例如:

DestinationFactoryManager dfManager = bus.getExtension(DestinationFactoryManager.class);

// Find a DestinationFactory for the SOAP HTTP transport
DestinationFactory df = dfManager.getDestinationFactory("http://schemas.xmlsoap.org/wsdl/soap/http");

// TODO: outline building of EndpointInfo
EndpointInfo endpointInfo = ...;
Destination destination = df.getDestination(endpointInfo);

MessageObserver通过以下方式进行注册:

MessageObserver myObserver = ...;
destination.setMessageObserver(myObserver);


十五、 A JAX-WS example

举例说明创建和消费一个服务,各个组件如何协同工作:

1. 调用Endpoint.publish("http://localhost/service", myService);
2. EndpointImpl 使用JaxWsServiceFactoryBean根据class 或者 WSDL创建myService的web服务。
3. 根据"http://localhost/service" 创建了EndpointInfo
4. 根据EndpointInfo创建JaxWsEndpointImpl,这个类包含JAX-WS 的具体拦截器。
5. JaxWsEndpointImpl创建Binding 和 Destination。并监听相应的端口。

十六、Dependencies
依赖关系请参考: http://cxf.apache.org/docs/cxf-dependency-graphs.html






猜你喜欢

转载自maosheng.iteye.com/blog/2023942