本文翻译自http://cxf.apache.org/docs/cxf-architecture.html,cxf架构综述
1、首先来看看
Bus:
通过BUS对扩展、拦截器、属性等注册。作为CXF的骨架,提供了CXF运行时的共享资源。这些资源包括WSDL、绑定工厂的管理。Bus可以很容易扩展以便包含你自己的资源和服务,或者你可以替换默认的资源(比如http destination factory基于Jetty换为Tomcat)。这种扩展性使依赖注入成为可能,而总线的默认实现正是基于Spring框架,所以各种运行时的组件(包括CXF)得以很方便的使用。
SpringBusFactory将会扫描你应用classpath下META-INF/cxf的所有配置文件,并将其构建于spring的application内,这些文件包括:
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-ends提供了一个创建server的编程模型,可以理解为一个门面。提供了JAX-WS, JAX-RS, Simple和Javascript的API用来创建Service,并且各个前端相互独立。通过拦截器来提供功能添加到Services和Endpoints
不推荐使用simple-front-end,除非你的应用无法使用annotation、或者处于使用更小的依赖,否则推荐使用jax-ws作为前端。这里有一个simple-frontend的例子http://cxf.apache.org/docs/simple-frontend.html
Messaging & Interceptors:
提供了一个低阶的消息和管道,以便在此基础上构建大部分的功能。
CXF是建立在一个通用的消息传递层由消息,拦截器,InterceptorChains组成。拦截器是功能的基本单元。通过分割消息如何处理和发送,这给了CXF非常灵活的架构。它可以在任何时候重新配置,这也使得CXF能够暂停和恢复拦截器链。拦截器有一个方法,handleMessage,可以允许对消息进行操作。这些拦截器可以建立成拦截器链。一些拦截器的例子包括:
拦截器是单向的,本质上是不知道他们是否正在处理一个请求、响应或错误。
Phase Interceptors
CXF提供了一个InterceptorChain实现,叫做PhaseInterceptorChain。当拦截器添加到链,他们会按照一定的顺序分配在阶段中,而PhaseInterceptor就是来指定这种顺序的拦截器
举例来说,现在在解析一个SOAP消息,可能涉及两个阶段:
1、dispatch阶段解析SOAP的headers并决定该消息路由到哪个service
2、解码阶段将SOAP的body通过JAXB绑定到对象
在第一个调度阶段我们可以通过两个拦截器来实现:首先一个ReadHeadersInterceptor来解析头,第二个是WS-AddressingInInterceptor来决定调用哪些服务。在第二个解码阶段,我们只用一个JAXBUnmarshallerIntercptor来实现。ReadHeadersInterceptor和AddressingInInterceptor要实现拦截器的阶段,需要在调用getPhase()时返回“dispatch”给PhaseInterceptorChain即可,此外ReadHeadersInterceptor可以在Interceptor.getBefore()方法被调用时返回拦截器AddressingInInterceptor的id来指定想要运行在AddressingInInterceptor之前。之前提到链非常动态和灵活,在上述示例中,我们可以对指定的服务添加拦截器来实现,甚至我们可以暂停链来等等待外部链的完成,就像服务端异步调用一样。
Fault Handling
在处理期间的任何一点,一个拦截器都可能抛出错误,或者衍生出错误如SoapFault。这将导致链停止调用和释放,释放的顺序与handleFault在每个拦截器被调用以相反的顺序。InterceptorChains有作为错误的观察者功能,一旦拦截器链被释放,导致错误的原因随着错误拦截器被触发。错误的观察者也可能触发新的链,以便用来调用指定的拦截器来处理错误。
Exchanges
除了一个Message的概念,还有一个Exchanges,他持有当前消息exchange的进入、出去和错误的消息的引用。它还拥有exchange的特定属性,而不只是消息。例如Exchange持有当前调用的Service。
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(); }
Service Model:
Services是一个用类WSDL来描述服务的模型。服务模型是CXF内在服务的表述。由两部分组成,第一、用ServiceInfo用来描述WSDL格式的模型包括服务的操作、绑定、端点和模式。第二、有Service本身,包含了ServiceInfo,数据绑定信息、拦截器、服务属性等。
一个服务可以从许多不同来源包括类和WSDL(1.1或2.0)构建。通常前端通过服务工厂来创建这样的服务。工厂组件如ServerFactoryBean和ClientProxyFactoryBean可以用于前端来创建、发布和消费服务。工厂类建立服务模型和配置服务拦截器、数据绑定等更多信息。
服务模型(Service)自己包含ServiceInfo类,下图描述了服务模型子包的API
Pluggable Data Bindings:
Data Bindings
数据绑定实现了XML和JAVA对象之间的映射。数据绑定将数据与XML相互转化,产生的XML schema,并支持wsdl2java生成代码,并不是所有的数据绑定类型都支持这些功能,但一个绑定至少要提供数据转换的功能。从数据绑定架构的细节来看,现在主要支持的绑定包括JAXB 2.x (default), Aegis, Apache XMLBeans, Service Data Objects (SDO) and JiBX
以2.7.0为例JAXB绑定位于cxf-rt-databinding-jaxb-2.7.0.jar
Protocol Bindings:
协议绑定提供了对协议的解释功能。
绑定提供方法来映射传输层顶层实体的格式和协议。一个绑定包含两个主要部分:BindingFactory和Binding。BindingFactory根据服务模型的BindingInfo来创建Binding。绑定包含当前绑定指定的拦截器,还实现了createMessage()方法,后者针对特定的绑定实现消息的创建
CXF当前支持以下四种协议:SOAP1.1、SOAP1.2、REST/HTTP, pure XML和CORBA.
The Soap Binding
最典型的绑定是SOAP。它有自己的消息类称为SoapMessage。它增加了能够保持当前消息的SoapVersion和header。
Soap绑定还添加了一种特殊类型的拦截器称为SoapInterceptor,他添加了两个方法:
Set<URI> getRoles();
Set<QName> getUnderstoodHeaders();
这些将告之SOAP拦截器去处理特定的SOAP拦截器的header和roles
还有很多拦截器用来处理SOAP消息:
StaxInInterceptor: 对消息中的输入流InputStream创建XMLStreamReader
ReadHeadersInterceptor: 读取SOAP流中的headers放到SoapMessage的Headers
MustUnderstandInterceptor: 负责检查must-understand SOAP头是否全部处理,未处理则抛出错误
SoapOutInterceptor: 负责将返回消息放入输出拦截链中,并启动输出拦截链。
以2.7.0为例,主要位于cxf-rt-bindings-soap-2.7.0.jar
Additional Bindings
其他的协议绑定包括REST/HTTP, pure XML, 和CORBA.
Transports:
TransportFactory创建目的地(接收)和管道(发送)。CXF为了隐藏绑定和前端层的特定协议,实现了自己的抽象传输层。当前支持的传输协议包括HTTP, HTTPs, HTTP-Jetty, HTTP-OSGI, Servlet, local, JMS, In-VM和许多其他通过camel协议对CXF的支持如SMTP/POP3, TCP and Jabber
Conduits
管道是消息输出的基础,管道是由ConduitInitiator创建。发送消息这个动作包括如下的流程:
1、调用conduit.prepare(message):
这里将开启消息发送,在这点上管道可能已经初始化一个连接,打开了输出流等待指定的消息写入到该输出流中
2、调用conduit.close(message):
这将关闭或丢弃正在发送中的消息。一个消息的发送者也可以在Conduit注册一个MessageObserver,如果管道是同步的,MessageObserver将会被通知一旦在相应被接收到
Destinations
Destinations是接收消息的基础,DestinationFactory创建一个destination
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); MessageObservers can then be registered with Destinations. These listen for incoming messages: MessageObserver myObserver = ...; destination.setMessageObserver(myObserver);
在CXF中最常用的MessageObserver是ChainInitiationObserver,主要完成如下的功能:接收输入的消息、创建消息的Exchange&PhaseInterceptorChain、开启chains
A JAX-WS example
下面这个例子展示了我们用 JAX-WS Endpoint.publish() 发布一个服务的流程:
1、调用Endpoint.publish("http://localhost/service", myService)
2、EndpointImpl用JaxWsServiceFactoryBean创建一个Service,需要用到myService或WSDL
3、根据Endpoint.publish的URL创建一个EndpointInfo
4、EndpointInfo创建一个JaxWsEndpointImpl,包含了JAX-WS端点指定的拦截器
5、JaxWsEndpointImpl开启Binding和Destination的监听