Apache CXF 架构指南
本文旨在介绍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(发送数据)。
请看下图各层顺序,可见他们是如何在一起工作的。
三、 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
四、服务调用时如何处理的?
参考以下客户端处理方式以及服务端处理方式:
客户端:
服务端:
五、 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中。如下图所示:
十二、 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
一、架构目标和约束
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(发送数据)。
请看下图各层顺序,可见他们是如何在一起工作的。
三、 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
四、服务调用时如何处理的?
参考以下客户端处理方式以及服务端处理方式:
客户端:
服务端:
五、 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中。如下图所示:
十二、 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
Set
这就使得特定的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
本文由用户 jopen 自行上传分享,仅供网友学习交流。所有权归原作者,若您的权利被侵害,请联系管理员。
转载本站原创文章,请注明出处,并保留原始链接、图片水印。
本站是一个以用户分享为主的开源技术平台,欢迎各类分享!