Apache CXF 架构指南

jopen 12年前
 本文旨在介绍CXF架构,以便对CXF有一个快速的理解。 
    
一、架构目标和约束 

    Apache CXF 服务框架旨在构建服务所必须的基础组件。目标有许多,其中包括 
下几方面: 
    1. 可嵌入式 
    2. 高性能 
    3. 易配置 
    4. 直观易用 
    5. 前后端(front-end)与核心代码完全分离 
    6. 数据格式化支持 
    7. 数据绑定支持 
    8. 协议绑定支持 
    9. 多种层传输支持 
   10. 多种编程语言支持 
   11. WS-*和相关特性支持 
   12. 代码生成工具盒WSDL验证工具 
   13. 灵活部署 

二、 CXF-API 

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

    请看下图各层顺序,可见他们是如何在一起工作的。 
Apache CXF 架构指南  

三、 BUS 

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

    这种可扩展性使得依赖注入变得可能。默认的Bus实现建立在spring framework之上,在运行时,组装这些组件在一起供你使用。 

    SpringBusFactory 在classpath/META-INF/cxf目录下搜索所有的bean配置文件, 并以此建立application context。以下文件默认会被扫描: 
    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) 
更详细的配置,可以参考 http://cxf.apache.org/docs/configuration-of-the-bus.html 

四、服务调用时如何处理的? 

    参考以下客户端处理方式以及服务端处理方式: 

    客户端: 
     Apache CXF 架构指南  

    服务端: 
     Apache CXF 架构指南  

五、 Front-end 

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

六、 Messaging & Interceptors 

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

    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中。如下图所示: 

     Apache CXF 架构指南  

十二、 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