搜索

第 78 章 CXF

download PDF

CXF 组件

cxf: 组件提供与 Apache CXF 集成,以连接到在 CXF 中托管的 JAX-WS 服务。

Maven 用户必须将此组件的 pom.xml 添加以下依赖项:

<dependency>
    <groupId>org.apache.camel</groupId>
    <artifactId>camel-cxf</artifactId>
    <version>x.x.x</version>
    <!-- use the same version as your Camel core version -->
</dependency>
注意

如果要了解 CXF 依赖项,请参阅 WHICH-JARS 文本文件。

注意

在流模式中使用 CXF 时(请参阅 DataFormat 选项),然后读取 流缓存

Camel on EAP 部署

此组件由 EAP 上的 Camel (Wildfly Camel)框架支持,该框架在 Red Hat JBoss Enterprise Application Platform (JBoss EAP)容器上提供了简化的部署模型。

CXF 组件与也使用 Apache CXF 的 JBoss EAP webservices susbsystem 集成。如需更多信息,请参阅 JAX-WS

注意

目前,EAP 子系统上的 Camel 不支持 CXF 或 Restlet 用户。但是,可以使用 CamelProxy 来模拟 CXF 消费者。

URI 格式

cxf:bean:cxfEndpoint[?options]

其中 cxfEndpoint 代表一个 Bean ID,它引用了 Spring bean registry 中的 bean。使用这个 URI 格式,大多数端点详情都在 bean 定义中指定。

cxf://someAddress[?options]

其中 someAddress 指定 CXF 端点的地址。使用这个 URI 格式,大多数端点详情都使用选项来指定。

对于上述任一样式,您可以按如下方式将选项附加到 URI:

cxf:bean:cxfEndpoint?wsdlURL=wsdl/hello_world.wsdl&dataFormat=PAYLOAD

选项

Name

必填

描述

wsdlURL

WSDL 的位置。WSDL 默认从端点地址获取。例如:

file://local/wsdl/hello.wsdlwsdl/hello.wsdl

serviceClass

SEI (服务端点接口)类的名称。此类可以有,但不需要 JSR181 注释。从 2.0 开始, 只有 POJO 模式需要这个选项。如果提供了 wsdlURL 选项,则 PAYLOAD 和 MESSAGE 模式不需要 serviceClass。当在没有 serviceClass 的情况下使用 wsdlURL 选项时,提供 serviceName 和 portName (用于 Spring 配置的endpointName)选项 MUST

从 2.0 开始,可以使用 \: 表示法来引用 registry 中的 serviceClass 对象实例。

建议引用的对象不能是一个代理(Spring AOP Proxy is OK), 因为它依赖于 non Spring AOP Proxy 的 Object.getClass ().getName () 方法。

2.8 开始, 可以为 PAYLOAD 和 MESSAGE 模式省略 wsdlURL 和 serviceClass 选项。当忽略它们时,任意 XML 元素可以放在 CxfPayload 的正文(PAYLOAD 模式)中,以便于 CXF Dispatch Mode。

例如: org.apache.camel.Hello

serviceName

只有在 WSDL 中存在多个 serviceName

此服务实施的服务名称,它映射到 wsdl:service@name。例如:

{http://org.apache.camel}ServiceName

endpointName

只有 serviceName 下有多个 portName,且 camel-cxf consumer 需要它,自 camel 2.2 起需要它

此服务实施的端口名称,它映射到 wsdl:port@name。例如:

{http://org.apache.camel}PortName

dataFormat

CXF 端点支持的消息数据格式。可能的值有: POJO (默认)、PAY LOADMESSAGE

relayHeaders

定义 CXF 端点中继路由中的标头。请参阅 “relayHeaders 选项的描述”一节。目前仅在 dataFormat=POJO默认:true 示例,false时才可用

嵌套

CXF 端点生成者调用的操作类型。可能的值有: truefalse (默认)

wrappedStyle

由于 2.5.0 是 WSDL 样式,用于描述 SOAP 正文中如何表示参数。如果值为 false,则 CXF 会选择 Documentation-literal unwrapped 风格,如果值为 true,则 CXF 选择 document-literal 打包风格

setDefaultBus

deprecated : 指定是否为这个端点使用默认的 CXF 总线。可能的值有: truefalse (默认)这个选项已弃用。以后使用 Camel 2.16 的默认Bus

defaultBus

deprecated : 指定是否为这个端点使用默认的 CXF 总线。可能的值有: truefalse (默认)这个选项已弃用。以后使用 Camel 2.16 的默认Bus

bus

使用 \ Slack 表示法引用 registry 的总线对象,例如 bus=\ problembusName。所引用的对象必须是 org.apache.cxf.Bus 的实例。

默认情况下,使用 CXF Bus Factory 创建的默认总线。

cxfBinding

使用 \# 表示法引用来自 registry 的 CXF 绑定对象,例如: cxfBinding=\"bindingName。引用的对象必须是 org.apache.camel.component.cxf.CxfBinding 实例。

headerFilterStrategy

使用 \: 表示法引用来自 registry swig-wagon 的标头过滤器策略对象,例如: headerFilterStrategy= \# strategyName。所引用的对象必须是 org.apache.camel.spi.HeaderFilterStrategy 的实例。

loggingFeatureEnabled

在 2.3 中,这个选项启用 CXF Logging 功能,它将写入入站和出站 SOAP 消息进行日志记录。可能的值有: truefalse (默认)

defaultOperationName

在 2.4 中,此选项设置由 CxfProducer 调用远程服务的 CxfProducer 使用的默认 operationName。例如:

defaultOperationName=greetMe

defaultOperationNamespace

在 2.4 中,此选项设置 CxfProducer 使用的默认 operationNamespace,后者调用远程服务。例如:

defaultOperationNamespace=http://apache.org/hello_world_soap_http

同步

在 2.5 中,这个选项可让 CXF 端点决定使用 sync 或 async API 进行底层工作。默认值为 false,这意味着 camel-cxf 端点会默认尝试使用 async API。

publishedEndpointUrl

2.5 中的新选项覆盖已发布的 WSDL 中出现的端点 URL,该端点使用服务地址 URL 和 ?wsdl 访问。例如:

publshedEndpointUrl=http://example.com/service

properties.propName

Camel 2.8: 允许您在端点 URI 中设置自定义 CXF 属性。例如,设置 properties.mtom-enabled=true 来启用 MTOM。为确保在开始调用时 CXF 不会切换线程,您可以设置 properties.org.apache.cxf.interceptor.OneWayProcessorInterceptor.USE_ORIGINAL_THREAD=true

allowStreaming

2.8.2 中的新功能。这个选项控制 CXF 组件是否在 PAYLOAD 模式下运行时(请参阅以下),DOM 会将传入的消息解析为 DOM Elements,或者将有效负载保留为 javax.xml.transform.Source 对象,允许在某些情况下流。

skipFaultLogging

2.11 中的新功能。这个选项控制 PhaseInterceptorChain 是否跳过记录它捕获的 Fault。

cxfEndpointConfigurer

Camel 2.11 中的新功能。这个选项可以应用 org.apache.camel.component.cxf.CxfEndpointConfigurer 的实现,它支持 以编程方式配置 CXF 端点。自 Camel 2.15.0 起, 用户可以通过实施 CxfEndpointConfigurer 的 configure{Server/Client} 方法来配置 CXF 服务器和客户端。

username

Camel 2.12.3 中的新选项用于为 CXF 客户端设置用户名的基本身份验证信息。

password

Camel 2.12.3 中的新选项用于为 CXF 客户端设置密码的基本身份验证信息。

continuationTimeout

Camel 2.14.0 中的新选项用于设置 CXF continuation 超时,当 CXF 服务器使用 Jetty 或 Servlet 传输时,默认可在 CxfConsumer 中使用。(在 Camel 2.14.0 之前,CxfConsumer 将 continuation 超时设置为 0,这意味着 continuation suspend 操作永远不会超时。)

默认 : 30000 示例 :continuation=80000

serviceNameportNameQNames,因此如果您为它们提供,请务必为其添加 {namespace} 前缀,如上例中所示。

dataformats 的描述

DataFormat

描述

POJO

POJO (纯 Java 对象)是目标服务器上调用的方法的 Java 参数。支持协议和逻辑 JAX-WS 处理程序。

PAYLOAD

PAYLOAD 是应用 CXF 端点消息配置后的消息有效负载( soap:body的内容)。仅支持协议 JAX-WS 处理程序。不支持逻辑 JAX-WS 处理程序。

MESSAGE

MESSAGE 是从传输层接收的原始消息。它不假设 touch 或 change Stream,如果您使用这种 DataFormat,则一些 CXF 拦截器会被删除,因此不支持 camel-cxf consumer 和 JAX-WS 处理程序后的任何 soap 标头。

CXF_MESSAGE

Camel 2.8.2 中的新功能,CXF_MESSAGE 允许通过将消息从传输层转换为原始 SOAP 消息来调用 CXF 拦截器的完整功能

您可以通过检索交换属性 CamelCXFDataFormat 来确定交换的数据格式模式。Exchange key 常量在 org.apache.camel.component.cxf.CxfConstants.DATA_FORMAT_PROPERTY 中定义。

使用 Apache Aries Blueprint 配置 CXF 端点.

从 Camel 2.8 开始,支持对 CXF 端点使用 Aries 蓝图依赖项注入。模式与 Spring 模式非常相似,因此转换过程比较透明。

例如:

 <blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.0.0"
            xmlns:camel-cxf="http://camel.apache.org/schema/blueprint/cxf"
 	   xmlns:cxfcore="http://cxf.apache.org/blueprint/core"
            xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 https://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd">

       <camel-cxf:cxfEndpoint id="routerEndpoint"
                      address="http://localhost:9001/router"
                      serviceClass="org.apache.servicemix.examples.cxf.HelloWorld">
         <camel-cxf:properties>
             <entry key="dataFormat" value="MESSAGE"/>
         </camel-cxf:properties>
      </camel-cxf:cxfEndpoint>

      <camel-cxf:cxfEndpoint id="serviceEndpoint"
			address="http://localhost:9000/SoapContext/SoapPort"
                     serviceClass="org.apache.servicemix.examples.cxf.HelloWorld">
    </camel-cxf:cxfEndpoint>

    <camelContext xmlns="http://camel.apache.org/schema/blueprint">
        <route>
            <from uri="routerEndpoint"/>
            <to uri="log:request"/>
        </route>
    </camelContext>

</blueprint>

目前,endpoint 元素是第一个支持的 CXF namespacehandler。

您还可以像 spring 中一样使用 bean 引用

<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.0.0"
           xmlns:jaxws="http://cxf.apache.org/blueprint/jaxws"
           xmlns:cxf="http://cxf.apache.org/blueprint/core"
           xmlns:camel="http://camel.apache.org/schema/blueprint"
           xmlns:camelcxf="http://camel.apache.org/schema/blueprint/cxf"
           xsi:schemaLocation="
             http://www.osgi.org/xmlns/blueprint/v1.0.0 https://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd
             http://cxf.apache.org/blueprint/jaxws http://cxf.apache.org/schemas/blueprint/jaxws.xsd
             http://cxf.apache.org/blueprint/core http://cxf.apache.org/schemas/blueprint/core.xsd
             ">

    <camelcxf:cxfEndpoint id="reportIncident"
                     address="/camel-example-cxf-blueprint/webservices/incident"
                     wsdlURL="META-INF/wsdl/report_incident.wsdl"
                     serviceClass="org.apache.camel.example.reportincident.ReportIncidentEndpoint">
    </camelcxf:cxfEndpoint>

    <bean id="reportIncidentRoutes" class="org.apache.camel.example.reportincident.ReportIncidentRoutes" />

    <camelContext xmlns="http://camel.apache.org/schema/blueprint">
        <routeBuilder ref="reportIncidentRoutes"/>
    </camelContext>

</blueprint>

如何在 MESSAGE 模式中启用 CXF 的 LoggingOutInterceptor

CXF 的 LoggingOutInterceptor 输出位于有线到日志记录系统(java.util.logging)的出站消息。由于 LoggingOutInterceptor 处于 PRE_STREAM 阶段(但 PRE_STREAM 阶段被删除为 MESSAGE 模式),因此您必须在 WRITE 阶段运行 LoggingOutInterceptor。以下是一个示例。

   <bean id="loggingOutInterceptor" class="org.apache.cxf.interceptor.LoggingOutInterceptor">
        <!--  it really should have been user-prestream but CXF does have such phase! -->
        <constructor-arg value="target/write"/>
   </bean>

<cxf:cxfEndpoint id="serviceEndpoint" address="http://localhost:9002/helloworld"
	serviceClass="org.apache.camel.component.cxf.HelloService">
	<cxf:outInterceptors>
	    <ref bean="loggingOutInterceptor"/>
	</cxf:outInterceptors>
	<cxf:properties>
		<entry key="dataFormat" value="MESSAGE"/>
	</cxf:properties>
</cxf:cxfEndpoint>

relayHeaders 选项的描述

有来自 JAXWS WSDL-first 开发者的 in-bandout-of-band on-the-wire 标头。

in-band 标头是标头,作为端点(如 SOAP 标头)的 WSDL 绑定合同的一部分。

带外 标头是通过线线序列化的标头,但不明确成为 WSDL 绑定合同的一部分。

标头中继/过滤是双向的。

当路由具有 CXF 端点并且开发人员需要有在线标头(如 SOAP 标头)时,将在另一个 JAXWS 端点消耗的路由中转发,然后将 relayHeaders 设置为 true,这是默认值。

仅在 POJO 模式中提供

relayHeaders=true 设置表示转发标头的意图。是否将给定标头中继的实际决定被委派给实现 MessageHeadersRelay 接口的可插拔实例。已查询 MessageHeadersRelay 的 concrete 实现,以决定是否需要转发标头。已有一个 SoapMessageHeadersRelay 的一个实现,它将自身绑定到已知的 SOAP 命名空间。目前,只过滤带外标头,当 relayHeaders=true 时始终转发带外的标头。如果有线上的标头,其命名空间在运行时未知,则使用 fall back DefaultMessageHeadersRelay,它只允许所有标头转发。

relayHeaders=false 设置表示所有标头(带外和带外)都会被丢弃。

您可以对自己的 MessageHeadersRelay 实现进行插件,或者在中继列表中添加其他内容。要覆盖预加载的中继实例,请确保您的 MessageHeadersRelay 实现服务与您要覆盖的命名空间相同。另请注意,覆盖中继必须将所有命名空间作为您要覆盖的命名空间提供服务,否则会抛出路由启动时的运行时异常,因为这会在命名空间中引入一种不确定性来转发实例映射。

<cxf:cxfEndpoint ...>
   <cxf:properties>
     <entry key="org.apache.camel.cxf.message.headers.relays">
       <list>
         <ref bean="customHeadersRelay"/>
       </list>
     </entry>
   </cxf:properties>
 </cxf:cxfEndpoint>
 <bean id="customHeadersRelay" class="org.apache.camel.component.cxf.soap.headers.CustomHeadersRelay"/>

查看显示您如何转发/过滤标头的测试:

链接:https://svn.apache.org/repos/asf/camel/branches/camel-1.x/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/soap/headers/CxfMessageHeadersRelayTest.java[https://svn.apache.org/repos/asf/camel/branches/camel-1.x/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/soap/headers/CxfMessageHeadersRelayTest.java ]

从版本 2.0 开始的更改

  • 支持 POJOPAYLOAD 模式。在 POJO 模式中,只有带外的消息标头可用于过滤,因为 CXF 从标头列表中删除。in-band 标头被合并到 POJO 模式的 MessageContentList 中。camel-cxf 组件会试图从 MessageContentList 中删除带外标头(如果需要过滤 in-band 标头),请使用 PAYLOAD 模式或插入(pretty directly) CXF 拦截器/JAXWS 处理程序到 CXF 端点。
  • Message Header Relay 机制已合并到 CxfHeaderFilterStrategy 中。relayHeaders 选项、其语义和默认值保持不变,但它是 CxfHeaderFilterStrategy 的属性。以下是配置它的示例:

    <bean id="dropAllMessageHeadersStrategy" class="org.apache.camel.component.cxf.common.header.CxfHeaderFilterStrategy">
    
        <!--  Set relayHeaders to false to drop all SOAP headers -->
        <property name="relayHeaders" value="false"/>
    
    </bean>

    然后,您的端点可以引用 CxfHeaderFilterStrategy

    <route>
        <from uri="cxf:bean:routerNoRelayEndpoint?headerFilterStrategy=#dropAllMessageHeadersStrategy"/>
        <to uri="cxf:bean:serviceNoRelayEndpoint?headerFilterStrategy=#dropAllMessageHeadersStrategy"/>
    </route>
  • MessageHeadersRelay 接口稍有变化,并重命名为 MessageHeaderFilter。它是 CxfHeaderFilterStrategy 的属性。以下是配置用户定义的 Message Header Filters 的示例:

    <bean id="customMessageFilterStrategy" class="org.apache.camel.component.cxf.common.header.CxfHeaderFilterStrategy">
        <property name="messageHeaderFilters">
            <list>
                <!--  SoapMessageHeaderFilter is the built in filter. It can be removed by omitting it. -->
                <bean class="org.apache.camel.component.cxf.common.header.SoapMessageHeaderFilter"/>
    
                <!--  Add custom filter here -->
                <bean class="org.apache.camel.component.cxf.soap.headers.CustomHeaderFilter"/>
            </list>
        </property>
    </bean>
  • 除了 relayHeaders 外,还有可在 CxfHeaderFilterStrategy 中配置的新属性。

Name

描述

type

必需?

默认值

relayHeaders

所有消息标头都由 Message Header Filters 处理

布尔值

true (1.6.1 行为)

relayAllMessageHeaders

所有消息标头都会传播(无需由 Message Header Filters 处理)

布尔值

false (1.6.1 行为)

allowFilterNamespaceClash

在激活命名空间中处理重叠过滤器。如果值为 true,则最后一个值胜出。如果值为 false,它会抛出异常。

布尔值

false (1.6.1 行为)

使用 Spring 配置 CXF 端点

您可以使用以下显示的 Spring 配置文件配置 CXF 端点,您也可以将端点嵌入到 camelContext 标签中。当您调用服务端点时,您可以将 operationNameoperationNamespace 标头设置为明确您调用的操作的状态。

请注意,在 Camel 2.x 中,我们改为使用 http://camel.apache.org/schema/cxf 作为 CXF 端点的目标命名空间。

<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:cxf="http://camel.apache.org/schema/cxf"
        xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
        http://camel.apache.org/schema/cxf http://camel.apache.org/schema/cxf/camel-cxf.xsd
        http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd     ">
 ...
注意

务必包含 root Bean 元素上指定的 JAX-WS schemaLocation 属性。这允许 CXF 验证文件,并是必需的。另请注意 < cxf:cxfEndpoint/> 标签末尾的命名空间声明是必需的,因为此标签的属性值不支持合并 {namespace}localName 语法。

cxf:cxfEndpoint 元素支持很多附加属性:

Name

portName

此服务实施的端点名称,它映射到 wsdl:port@name。在 ns:PORT_NAME 格式中,其中 ns 是在此范围内有效的命名空间前缀。

serviceName

此服务实施的服务名称,它映射到 wsdl:service@name。在 ns:SERVICE_NAME 格式中,其中 ns 是此范围有效的命名空间前缀。

wsdlURL

WSDL 的位置。可以在 classpath、文件系统上,也可以远程托管。

bindingId

要使用的服务模型的 bindingId

address

服务发布地址。

bus

JAX-WS 端点中使用的总线名称。

serviceClass

可以具有 JSR181 注解或没有该类的 SEI (服务端点接口)类的名称。

它还支持许多子元素:

Name

cxf:inInterceptors

此端点的传入拦截器。< bean> 或 &lt; ref> 列表。

cxf:inFaultInterceptors

此端点的传入错误拦截器。< bean> 或 &lt; ref> 列表。

cxf:outInterceptors

此端点的传出拦截器。< bean> 或 &lt; ref> 列表。

cxf:outFaultInterceptors

此端点的传出错误拦截器。< bean> 或 &lt; ref> 列表。

cxf:properties

提供给 JAX-WS 端点的属性映射。

cxf:handlers

提供给 JAX-WS 端点的 JAX-WS 处理程序列表。

cxf:dataBinding

您可以指定端点中使用哪个 DataBinding。这可以通过 Spring < bean class="MyDataBinding"/> 语法提供。

cxf:binding

您可以指定要使用的此端点的 BindingFactory。这可以通过 Spring < bean class="MyBindingFactory"/> 语法提供。

cxf:features

保存此端点拦截器的功能。< bean&gt; s 或 < ref>s 列表

cxf:schemaLocations

要使用的端点的 schema 位置。< schemaLocation> s列表

cxf:serviceFactory

要使用此端点的服务工厂。这可以通过 Spring < bean class="MyServiceFactory"/> 语法提供

您可以在此处找到更详细的示例,它们演示了如何提供拦截器、属性和处理程序: http://cwiki.apache.org/CXF20DOC/jax-ws-configuration.html

注意

您可以使用 CXF:properties 从 Spring 配置文件设置 CXF 端点的 dataFormatsetDefaultBus 属性,如下所示:

<cxf:cxfEndpoint id="testEndpoint" address="http://localhost:9000/router"
     serviceClass="org.apache.camel.component.cxf.HelloService"
     endpointName="s:PortName"
     serviceName="s:ServiceName"
     xmlns:s="http://www.example.com/test">
     <cxf:properties>
       <entry key="dataFormat" value="MESSAGE"/>
       <entry key="setDefaultBus" value="true"/>
     </cxf:properties>
   </cxf:cxfEndpoint>

如何将 camel-cxf 组件使用 log4j 而不是 java.util.logging

cxf 的默认日志记录器是 java.util.logging。如果要将其更改为 log4j,请按如下所示操作:在 classpath 中,创建一个名为 META-INF/cxf/org.apache.cxf.logger 的文件。此文件必须在一行中包含类的完全限定名称 org.apache.cxf.common.logging.Log4jLogger,且无注释。

如何使用 xml 启动文档让 camel-cxf 响应消息

如果您使用一些 SOAP 客户端,如 PHP,可能会导致此类错误,因为 CXF 不会添加 XML 启动文档 < ?xml version="1.0" encoding="utf-8"?>

Error:sendSms: SoapFault exception: [Client] looks like we got no XML document in [...]

要解决这个问题,您只需要告诉 StaxOutInterceptor 为您编写 XML 启动文档。

public class WriteXmlDeclarationInterceptor extends AbstractPhaseInterceptor<SoapMessage> {
    public WriteXmlDeclarationInterceptor() {
        super(Phase.PRE_STREAM);
        addBefore(StaxOutInterceptor.class.getName());
    }

    public void handleMessage(SoapMessage message) throws Fault {
        message.put("org.apache.cxf.stax.force-start-document", Boolean.TRUE);
    }

}

您可以添加客户拦截器,并将其配置为 camel-cxf endpont

<cxf:cxfEndpoint id="routerEndpoint" address="http://localhost:${CXFTestSupport.port2}/CXFGreeterRouterTest/CamelContext/RouterPort"
 		serviceClass="org.apache.hello_world_soap_http.GreeterImpl"
 		skipFaultLogging="true">
     <cxf:outInterceptors>
         <!-- This interceptor forces the CXF server send the XML start document to client -->
         <bean class="org.apache.camel.component.cxf.WriteXmlDeclarationInterceptor"/>
     </cxf:outInterceptors>
     <cxf:properties>
         <!-- Set the publishedEndpointUrl which could override the service address from generated WSDL as you want -->
         <entry key="publishedEndpointUrl" value="http://www.simple.com/services/test" />
     </cxf:properties>
 </cxf:cxfEndpoint>

或者,如果您正在使用 Camel 2.4,则为它添加一个消息标头。

 // set up the response context which force start document
 Map<String, Object> map = new HashMap<String, Object>();
 map.put("org.apache.cxf.stax.force-start-document", Boolean.TRUE);
 exchange.getOut().setHeader(Client.RESPONSE_CONTEXT, map);

如何以 POJO 数据格式消耗来自 camel-cxf 端点的消息

camel-cxf 端点消费者 POJO 数据格式基于 cxf 调用器,因此消息标题具有名为 CxfConstants.OPERATION_NAME 的属性,消息正文是 SEI 方法参数的列表。

public class PersonProcessor implements Processor {

    private static final transient Logger LOG = LoggerFactory.getLogger(PersonProcessor.class);

    @SuppressWarnings("unchecked")
    public void process(Exchange exchange) throws Exception {
        LOG.info("processing exchange in camel");

        BindingOperationInfo boi = (BindingOperationInfo)exchange.getProperty(BindingOperationInfo.class.toString());
        if (boi != null) {
            LOG.info("boi.isUnwrapped" + boi.isUnwrapped());
        }
        // Get the parameters list which element is the holder.
        MessageContentsList msgList = (MessageContentsList)exchange.getIn().getBody();
        Holder<String> personId = (Holder<String>)msgList.get(0);
        Holder<String> ssn = (Holder<String>)msgList.get(1);
        Holder<String> name = (Holder<String>)msgList.get(2);

        if (personId.value == null || personId.value.length() == 0) {
            LOG.info("person id 123, so throwing exception");
            // Try to throw out the soap fault message
            org.apache.camel.wsdl_first.types.UnknownPersonFault personFault =
                new org.apache.camel.wsdl_first.types.UnknownPersonFault();
            personFault.setPersonId("");
            org.apache.camel.wsdl_first.UnknownPersonFault fault =
                new org.apache.camel.wsdl_first.UnknownPersonFault("Get the null value of person name", personFault);
            // Since camel has its own exception handler framework, we can't throw the exception to trigger it
            // We just set the fault message in the exchange for camel-cxf component handling and return
            exchange.getOut().setFault(true);
            exchange.getOut().setBody(fault);
            return;
        }

        name.value = "Bonjour";
        ssn.value = "123";
        LOG.info("setting Bonjour as the response");
        // Set the response message, first element is the return value of the operation,
        // the others are the holders of method parameters
        exchange.getOut().setBody(new Object[] {null, personId, ssn, name});
    }

}

如何以 POJO 数据格式为 camel-cxf 端点准备消息

camel-cxf 端点生成者基于 cxf 客户端 API。首先,您需要在消息标头中指定操作名称,然后将方法参数添加到列表中,然后使用此参数列表初始化消息。响应消息的正文是 messageContentsList,您可以从该列表获取结果。

如果您没有在消息标头中指定操作名称,CxfProducer 会尝试使用 CxfEndpoint 中的 defaultOperationName。如果 CxfEndpoint 上没有设置 defaultOperationName,它会从操作列表中选择第一个操作名称。

如果要从消息正文获取对象数组,您可以使用 message.getbody (Object[].class) 获取正文,如下所示:

Exchange senderExchange = new DefaultExchange(context, ExchangePattern.InOut);
final List<String> params = new ArrayList<String>();
// Prepare the request message for the camel-cxf procedure
params.add(TEST_MESSAGE);
senderExchange.getIn().setBody(params);
senderExchange.getIn().setHeader(CxfConstants.OPERATION_NAME, ECHO_OPERATION);

Exchange exchange = template.send("direct:EndpointA", senderExchange);

org.apache.camel.Message out = exchange.getOut();
// The response message's body is an MessageContentsList which first element is the return value of the operation,
// If there are some holder parameters, the holder parameter is filled in the reset of List.
// The result is extract from the MessageContentsList with the String class type
MessageContentsList result = (MessageContentsList)out.getBody();
LOG.info("Received output text: " + result.get(0));
Map<String, Object> responseContext = CastUtils.cast((Map<?, ?>)out.getHeader(Client.RESPONSE_CONTEXT));
assertNotNull(responseContext);
assertEquals("The response context", "UTF-8", responseContext.get(org.apache.cxf.message.Message.ENCODING));
assertEquals("Reply body on Camel is wrong", "echo " + TEST_MESSAGE, result.get(0));

如何以 PAYLOAD 数据格式处理 camel-cxf 端点的消息

在 Apache Camel 2.0 中: CxfMessage.getBody () 返回 org.apache.camel.component.cxf.CxfPayload 对象,它具有 SOAP 消息标头和 Body 元素的 getter。这个更改支持将原生 CXF 消息与 Apache Camel 消息分离。

protected RouteBuilder createRouteBuilder() {
    return new RouteBuilder() {
        public void configure() {
            from(SIMPLE_ENDPOINT_URI + "&dataFormat=PAYLOAD").to("log:info").process(new Processor() {
                @SuppressWarnings("unchecked")
                public void process(final Exchange exchange) throws Exception {
                    CxfPayload<SoapHeader> requestPayload = exchange.getIn().getBody(CxfPayload.class);
                    List<Source> inElements = requestPayload.getBodySources();
                    List<Source> outElements = new ArrayList<Source>();
                    // You can use a customer toStringConverter to turn a CxfPayLoad message into String as you want
                    String request = exchange.getIn().getBody(String.class);
                    XmlConverter converter = new XmlConverter();
                    String documentString = ECHO_RESPONSE;

                    Element in = new XmlConverter().toDOMElement(inElements.get(0));
                    // Just check the element namespace
                    if (!in.getNamespaceURI().equals(ELEMENT_NAMESPACE)) {
                        throw new IllegalArgumentException("Wrong element namespace");
                    }
                    if (in.getLocalName().equals("echoBoolean")) {
                        documentString = ECHO_BOOLEAN_RESPONSE;
                        checkRequest("ECHO_BOOLEAN_REQUEST", request);
                    } else {
                        documentString = ECHO_RESPONSE;
                        checkRequest("ECHO_REQUEST", request);
                    }
                    Document outDocument = converter.toDOMDocument(documentString);
                    outElements.add(new DOMSource(outDocument.getDocumentElement()));
                    // set the payload header with null
                    CxfPayload<SoapHeader> responsePayload = new CxfPayload<SoapHeader>(null, outElements, null);
                    exchange.getOut().setBody(responsePayload);
                }
            });
        }
    };
}

如何在 POJO 模式中获取和设置 SOAP 标头

POJO 表示,当 CXF 端点生成或使用 Camel 交换时,数据格式是 Java 对象的列表。尽管 Apache Camel 在此模式中将消息正文公开为 POJO,但 CXF 组件仍然提供对读取和写入 SOAP 标头的访问。但是,由于 CXF 拦截器在处理后从标头列表中删除带外 SOAP 标头,因此只有 POJO 模式才提供带外 SOAP 标头。

以下示例演示了如何获取/设置 SOAP 标头。假设我们有一个路由,它从一个 CXF 端点转发到另一个端点。也就是说,SOAP Client Apache Camel CXF 服务。在请求进入 CXF 服务之前,我们可以附加两个处理器以在(1)获取/插入 SOAP 标头,然后再返回到 SOAP 客户端。本例中的 processor (1)和(2)是 InsertRequestOutHeaderProcessor 和 InsertResponseOutHeaderProcessor。我们的路由类似如下:

<route>
    <from uri="cxf:bean:routerRelayEndpointWithInsertion"/>
    <process ref="InsertRequestOutHeaderProcessor" />
    <to uri="cxf:bean:serviceRelayEndpointWithInsertion"/>
    <process ref="InsertResponseOutHeaderProcessor" />
</route>

在 2.x SOAP 标头中,会传播到 Apache Camel 消息标头。Apache Camel 消息标头名称是 org.apache.cxf.headers.Header.list,它是 CXF 中定义的常量(org.apache.cxf.headers.Header.Header.HEADER_LIST)。标头值是 CXF SoapHeader 对象(org.apache.cxf.binding.soap.SoapHeader)的 List <>。以下片段是 InsertResponseOutHeaderProcessor (它会在响应消息中插入一个新的 SOAP 标头)。在 InsertResponseOutHeaderProcessorInsertRequestOutHeaderProcessor 中访问 SOAP 标头的方式实际相同。两个处理器之间的唯一区别是设置插入 SOAP 标头的方向。

public static class InsertResponseOutHeaderProcessor implements Processor {

    @SuppressWarnings("unchecked")
    public void process(Exchange exchange) throws Exception {
        // If exchange is routed from camel-cxf endpoint, this is the header
        List<SoapHeader> soapHeaders = CastUtils.cast((List<?>)exchange.getIn().getHeader(Header.HEADER_LIST));
        if (soapHeaders == null) {
            // we just create a new soap headers in case the header is null
            soapHeaders = new ArrayList<SoapHeader>();
        }

        // Insert a new header
        String xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?><outofbandHeader "
            + "xmlns=\"http://cxf.apache.org/outofband/Header\" hdrAttribute=\"testHdrAttribute\" "
            + "xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" soap:mustUnderstand=\"1\">"
            + "<name>New_testOobHeader</name><value>New_testOobHeaderValue</value></outofbandHeader>";
        SoapHeader newHeader = new SoapHeader(soapHeaders.get(0).getName(),
                       DOMUtils.readXml(new StringReader(xml)).getDocumentElement());
        // make sure direction is OUT since it is a response message.
        newHeader.setDirection(Direction.DIRECTION_OUT);
        //newHeader.setMustUnderstand(false);
        soapHeaders.add(newHeader);

    }

}

如何在 PAYLOAD 模式中获取和设置 SOAP 标头

我们已演示了如何以 PAYLOAD 模式访问 SOAP 消息(CxfPayload 对象) (请参阅 如何处理 PAYLOAD 数据格式的 camel-cxf 端点的消息)。

获取 CxfPayload 对象后,您可以调用 CxfPayload.getHeaders () 方法,该方法返回 DOM Elements (SOAP 标头) 列表

from(getRouterEndpointURI()).process(new Processor() {
    @SuppressWarnings("unchecked")
    public void process(Exchange exchange) throws Exception {
        CxfPayload<SoapHeader> payload = exchange.getIn().getBody(CxfPayload.class);
        List<Source> elements = payload.getBodySources();
        assertNotNull("Elements here", elements);
        assertEquals("Get the wrong elements size", 1, elements.size());

        Element el = new XmlConverter().toDOMElement(elements.get(0));
        elements.set(0, new DOMSource(el));
        assertEquals("Get the wrong namespace URI", "http://camel.apache.org/pizza/types",
                el.getNamespaceURI());

        List<SoapHeader> headers = payload.getHeaders();
        assertNotNull("Headers here", headers);
        assertEquals("Get the wrong headers size", headers.size(), 1);
        assertEquals("Get the wrong namespace URI",
                ((Element)(headers.get(0).getObject())).getNamespaceURI(),
                "http://camel.apache.org/pizza/types");
    }

})
.to(getServiceEndpointURI());

自 Camel 2.16.0 起,您可以使用 “如何在 POJO 模式中获取和设置 SOAP 标头”一节 中所述的方法设置或获取 SOAP 标头。现在,您可以使用 org.apache.cxf.headers.Header.list 标头来获取和设置 SOAP 标头列表。这意味着,如果您有一个路由从一个 Camel CXF 端点转发到另一个(SOAP Client Camel CXF 服务),则 SOAP 客户端发送的 SOAP 标头现在也转发到 CXF 服务。如果您不希望转发标头,请从 org.apache.cxf.headers.Header.list Camel 标头中删除它们。

SOAP 标头在 MESSAGE 模式中不可用

在跳过 SOAP 处理时,在 MESSAGE 模式中不提供 SOAP 标头。

如何从 Apache Camel 抛出 SOAP 故障

如果您使用 CXF 端点来消耗 SOAP 请求,您可能需要从 camel 上下文抛出 SOAP Fault。基本上,您可以使用 throwFault DSL 来执行此操作;它适用于 POJOPAYLOADMESSAGE 数据格式。您可以定义 soap 错误,如下所示:

SOAP_FAULT = new SoapFault(EXCEPTION_MESSAGE, SoapFault.FAULT_CODE_CLIENT);
Element detail = SOAP_FAULT.getOrCreateDetail();
Document doc = detail.getOwnerDocument();
Text tn = doc.createTextNode(DETAIL_TEXT);
detail.appendChild(tn);

然后按以下方式抛出它:

from(routerEndpointURI).setFaultBody(constant(SOAP_FAULT));

如果您的 CXF 端点以 MESSAGE 数据格式工作,您可以在消息正文中设置 SOAP Fault 消息,并在消息标头中设置响应代码。

from(routerEndpointURI).process(new Processor() {

    public void process(Exchange exchange) throws Exception {
        Message out = exchange.getOut();
        // Set the message body with the
        out.setBody(this.getClass().getResourceAsStream("SoapFaultMessage.xml"));
        // Set the response code here
        out.setHeader(org.apache.cxf.message.Message.RESPONSE_CODE, new Integer(500));
    }

});

对于 POJO 数据格式来说也是如此。您可以在 Out 正文上设置 SOAP Fault,并通过调用 Message.setFault (true) 来指示其存在故障,如下所示:

from("direct:start").onException(SoapFault.class).maximumRedeliveries(0).handled(true)
    .process(new Processor() {
        public void process(Exchange exchange) throws Exception {
            SoapFault fault = exchange
                .getProperty(Exchange.EXCEPTION_CAUGHT, SoapFault.class);
            exchange.getOut().setFault(true);
            exchange.getOut().setBody(fault);
        }

    }).end().to(serviceURI);

如何传播 CXF 端点的请求和响应上下文

CXF 客户端 API 提供了使用请求和响应上下文调用操作的方法。如果您使用 CXF 端点制作者调用外部 Web 服务,您可以设置请求上下文,并使用以下代码获取响应上下文:

        CxfExchange exchange = (CxfExchange)template.send(getJaxwsEndpointUri(), new Processor() {
             public void process(final Exchange exchange) {
                 final List<String> params = new ArrayList<String>();
                 params.add(TEST_MESSAGE);
                 // Set the request context to the inMessage
                 Map<String, Object> requestContext = new HashMap<String, Object>();
                 requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, JAXWS_SERVER_ADDRESS);
                 exchange.getIn().setBody(params);
                 exchange.getIn().setHeader(Client.REQUEST_CONTEXT , requestContext);
                 exchange.getIn().setHeader(CxfConstants.OPERATION_NAME, GREET_ME_OPERATION);
             }
         });
         org.apache.camel.Message out = exchange.getOut();
         // The output is an object array, the first element of the array is the return value
         Object\[\] output = out.getBody(Object\[\].class);
         LOG.info("Received output text: " + output\[0\]);
         // Get the response context form outMessage
         Map<String, Object> responseContext = CastUtils.cast((Map)out.getHeader(Client.RESPONSE_CONTEXT));
         assertNotNull(responseContext);
         assertEquals("Get the wrong wsdl opertion name", "{http://apache.org/hello_world_soap_http}greetMe",
                      responseContext.get("javax.xml.ws.wsdl.operation").toString());

附加支持

POJO 模式 : 支持带有 Attachment 和 MTOM 的 SOAP (请参阅 Payload Mode 为启用 MTOM 的示例)。无论没有测试,带有 Attachment 的 SOAP 不会被测试。因为 2.1.Since 附加功能被推广到 Camel 消息的附件。Since 附加到 POJO,用户通常不需要处理附件。

DataHandler Message.getAttachment(String id)

.

有效负载模式: 自 2.1 起支持 MTOM。附加功能可以通过上述 Camel 消息 API 检索。不支持使用 Attachment 的 SOAP,因为此模式中没有 SOAP 处理。

要启用 MTOM,将 CXF 端点属性 "mtom_enabled" 设置为 true。(我相信您只能通过 Spring 执行此操作。)

<cxf:cxfEndpoint id="routerEndpoint" address="http://localhost:${CXFTestSupport.port1}/CxfMtomRouterPayloadModeTest/jaxws-mtom/hello"
         wsdlURL="mtom.wsdl"
         serviceName="ns:HelloService"
         endpointName="ns:HelloPort"
         xmlns:ns="http://apache.org/camel/cxf/mtom_feature">

     <cxf:properties>
         <!--  enable mtom by setting this property to true -->
         <entry key="mtom-enabled" value="true"/>

         <!--  set the camel-cxf endpoint data fromat to PAYLOAD mode -->
         <entry key="dataFormat" value="PAYLOAD"/>
     </cxf:properties>

您可以在 Payload 模式中生成带有附件的 Camel 消息,以发送到 CXF 端点。

Exchange exchange = context.createProducerTemplate().send("direct:testEndpoint", new Processor() {

    public void process(Exchange exchange) throws Exception {
        exchange.setPattern(ExchangePattern.InOut);
        List&lt;Source> elements = new ArrayList&lt;Source>();
        elements.add(new DOMSource(DOMUtils.readXml(new StringReader(MtomTestHelper.REQ_MESSAGE)).getDocumentElement()));
        CxfPayload<SoapHeader> body = new CxfPayload<SoapHeader>(new ArrayList<SoapHeader>(),
            elements, null);
        exchange.getIn().setBody(body);
        exchange.getIn().addAttachment(MtomTestHelper.REQ_PHOTO_CID,
            new DataHandler(new ByteArrayDataSource(MtomTestHelper.REQ_PHOTO_DATA, "application/octet-stream")));

        exchange.getIn().addAttachment(MtomTestHelper.REQ_IMAGE_CID,
            new DataHandler(new ByteArrayDataSource(MtomTestHelper.requestJpeg, "image/jpeg")));

    }

});

// process response

CxfPayload<SoapHeader> out = exchange.getOut().getBody(CxfPayload.class);
Assert.assertEquals(1, out.getBody().size());

Map<String, String> ns = new HashMap<String, String>();
ns.put("ns", MtomTestHelper.SERVICE_TYPES_NS);
ns.put("xop", MtomTestHelper.XOP_NS);

XPathUtils xu = new XPathUtils(ns);
Element oute = new XmlConverter().toDOMElement(out.getBody().get(0));
Element ele = (Element)xu.getValue("//ns:DetailResponse/ns:photo/xop:Include", oute,
                                   XPathConstants.NODE);
String photoId = ele.getAttribute("href").substring(4); // skip "cid:"

ele = (Element)xu.getValue("//ns:DetailResponse/ns:image/xop:Include", oute,
                                   XPathConstants.NODE);
String imageId = ele.getAttribute("href").substring(4); // skip "cid:"

DataHandler dr = exchange.getOut().getAttachment(photoId);
Assert.assertEquals("application/octet-stream", dr.getContentType());
MtomTestHelper.assertEquals(MtomTestHelper.RESP_PHOTO_DATA, IOUtils.readBytesFromStream(dr.getInputStream()));

dr = exchange.getOut().getAttachment(imageId);
Assert.assertEquals("image/jpeg", dr.getContentType());

BufferedImage image = ImageIO.read(dr.getInputStream());
Assert.assertEquals(560, image.getWidth());
Assert.assertEquals(300, image.getHeight());

您还可以在 Payload 模式中使用从 CXF 端点接收的 Camel 消息。

public static class MyProcessor implements Processor {

    @SuppressWarnings("unchecked")
    public void process(Exchange exchange) throws Exception {
        CxfPayload<SoapHeader> in = exchange.getIn().getBody(CxfPayload.class);

        // verify request
        assertEquals(1, in.getBody().size());

        Map<String, String> ns = new HashMap<String, String>();
        ns.put("ns", MtomTestHelper.SERVICE_TYPES_NS);
        ns.put("xop", MtomTestHelper.XOP_NS);

        XPathUtils xu = new XPathUtils(ns);
        Element body = new XmlConverter().toDOMElement(in.getBody().get(0));
        Element ele = (Element)xu.getValue("//ns:Detail/ns:photo/xop:Include", body,
                                           XPathConstants.NODE);
        String photoId = ele.getAttribute("href").substring(4); // skip "cid:"
        assertEquals(MtomTestHelper.REQ_PHOTO_CID, photoId);

        ele = (Element)xu.getValue("//ns:Detail/ns:image/xop:Include", body,
                                           XPathConstants.NODE);
        String imageId = ele.getAttribute("href").substring(4); // skip "cid:"
        assertEquals(MtomTestHelper.REQ_IMAGE_CID, imageId);

        DataHandler dr = exchange.getIn().getAttachment(photoId);
        assertEquals("application/octet-stream", dr.getContentType());
        MtomTestHelper.assertEquals(MtomTestHelper.REQ_PHOTO_DATA, IOUtils.readBytesFromStream(dr.getInputStream()));

        dr = exchange.getIn().getAttachment(imageId);
        assertEquals("image/jpeg", dr.getContentType());
        MtomTestHelper.assertEquals(MtomTestHelper.requestJpeg, IOUtils.readBytesFromStream(dr.getInputStream()));

        // create response
        List&lt;Source> elements = new ArrayList&lt;Source>();
        elements.add(new DOMSource(DOMUtils.readXml(new StringReader(MtomTestHelper.RESP_MESSAGE)).getDocumentElement()));
        CxfPayload&lt;SoapHeader> sbody = new CxfPayload&lt;SoapHeader>(new ArrayList&lt;SoapHeader>(),
            elements, null);
        exchange.getOut().setBody(sbody);
        exchange.getOut().addAttachment(MtomTestHelper.RESP_PHOTO_CID,
            new DataHandler(new ByteArrayDataSource(MtomTestHelper.RESP_PHOTO_DATA, "application/octet-stream")));

        exchange.getOut().addAttachment(MtomTestHelper.RESP_IMAGE_CID,
            new DataHandler(new ByteArrayDataSource(MtomTestHelper.responseJpeg, "image/jpeg")));

    }
}

Message Mode: Attachments 不支持,因为它根本不处理消息。

CXF_MESSAGE Mode: 支持 MTOM,而附件则可通过上述 Camel 消息 API 检索。

注意

当收到多部分(即 MTOM)时,将默认的 SOAPMessage 传给 String 转换器在正文上提供完整的多部分有效负载。如果您只需要 SOAP XML 作为 String,您可以使用 message.getSOAPPart () 设置消息正文,并且 Camel 转换可以为您做剩余工作。

如何传播堆栈追踪信息

可以配置 CXF 端点,以便在服务器端引发 Java 异常时,异常的堆栈追踪会被放入故障消息并返回到客户端。要启用这种情况,请将 dataFormat 设置为 PAYLOAD,并在 cxfEndpoint 元素中将 faultStackTraceEnabled 属性设置为 true,如下所示:

<cxf:cxfEndpoint id="router" address="http://localhost:9002/TestMessage"
    wsdlURL="ship.wsdl"
    endpointName="s:TestSoapEndpoint"
    serviceName="s:TestService"
    xmlns:s="http://test">
  <cxf:properties>
    <!-- enable sending the stack trace back to client; the default value is false-->
    <entry key="faultStackTraceEnabled" value="true" /> <entry key="dataFormat" value="PAYLOAD" />
  </cxf:properties>
</cxf:cxfEndpoint>

为安全起见,堆栈跟踪不包括导致异常(即,由 导致的堆栈追踪的一部分)。如果要在堆栈追踪中包含导致异常,在 cxfEndpoint 元素中将 exceptionMessageCauseEnabled 属性设置为 true,如下所示:

<cxf:cxfEndpoint id="router" address="http://localhost:9002/TestMessage"
    wsdlURL="ship.wsdl"
    endpointName="s:TestSoapEndpoint"
    serviceName="s:TestService"
    xmlns:s="http://test">
  <cxf:properties>
    <!-- enable to show the cause exception message and the default value is false -->
    <entry key="exceptionMessageCauseEnabled" value="true" />
    <!-- enable to send the stack trace back to client,  the default value is false-->
    <entry key="faultStackTraceEnabled" value="true" />
    <entry key="dataFormat" value="PAYLOAD" />
  </cxf:properties>
</cxf:cxfEndpoint>
警告

仅为测试和诊断目的启用 exceptionMessageCauseEnabled 标志。对于服务器而言,正常做法是让恶意用户探测到服务器的最初原因。

PAYLOAD 模式流支持

在 2.8.2 中,camel-cxf 组件现在支持在使用 PAYLOAD 模式时流传输传入的消息。在以前的版本中,传入的信息会被完全解析 DOM。对于大型消息,这非常耗时,使用大量内存。从 2.8.2 开始,在路由时,传入的消息可以保留为 javax.xml.transform.Source,如果没有修改有效负载,则可以直接流传输到目标目的地。对于常见的"简单代理"用例(例如: from ("cxf:…​").to ("cxf:…​")),这可以提供非常显著的性能增加,并显著降低内存要求。

然而,在有些情况下流可能不合适或需要的。由于流性质,在稍后处理链中可能无法发现无效的传入的 XML。此外,某些操作可能要求消息是 DOM 解析的任何方式(如 WS-Security 或消息追踪等),在这种情况下,流的优势是有限的。此时,可以通过两种方式控制流:

  • endpoint 属性:您可以添加 "allowStreaming=false" 作为端点属性,来打开/关闭流。
  • 组件属性:CxfComponent 对象也具有 allowStreaming 属性,可以为从该组件创建的端点设置默认值。
  • 全局系统属性:如果关闭,您可以添加 org.apache.camel.component.cxf.streaming 的系统属性,以关闭。这会设置全局默认值,但设置上面的 endpoint 属性会覆盖该端点的值。

使用通用 CXF Dispatch 模式

从 2.8.0,camel-cxf 组件支持通用 CXF 分配模式,它可以传输任意结构的消息(例如,不绑定到特定 XML 模式)。要使用此模式,您只需要省略指定 CXF 端点的 wsdlURL 和 serviceClass 属性。

<cxf:cxfEndpoint id="testEndpoint" address="http://localhost:9000/SoapContext/SoapAnyPort">
  <cxf:properties>
    <entry key="dataFormat" value="PAYLOAD"/>
  </cxf:properties>
</cxf:cxfEndpoint>

请注意,默认的 CXF 分配客户端不会发送特定的 SOAPAction 标头。因此,当目标服务需要特定的 SOAPAction 值时,会使用键 SOAPAction (不区分大小写)在 Camel 标头中提供。

78.1. WildFly 上的 CXF 用户

WildFly 上的 camel-cxf 用户配置与独立 Camel 的配置不同。生产者端点可以正常运行。

在 WildFly 上,camel-cxf 用户利用容器提供的默认 Undertow HTTP 服务器。服务器在 undertow 子系统配置中定义。以下是 standalone.xml 中默认配置的摘录:

<subsystem xmlns="urn:jboss:domain:undertow:4.0">
    <buffer-cache name="default" />
    <server name="default-server">
        <http-listener name="default" socket-binding="http" redirect-socket="https" enable-http2="true" />
        <https-listener name="https" socket-binding="https" security-realm="ApplicationRealm" enable-http2="true" />
        <host name="default-host" alias="localhost">
            <location name="/" handler="welcome-content" />
            <filter-ref name="server-header" />
            <filter-ref name="x-powered-by-header" />
            <http-invoker security-realm="ApplicationRealm" />
        </host>
    </server>
</subsystem>

在本实例中,Undertow 配置为侦听 http 和 https socket-binding 指定的接口/端口。默认情况下,对于 http,对于端口 8080,https 为 8443。

例如,如果您使用不同的主机或端口组合配置端点使用者,服务器日志文件中会显示警告。例如,以下主机和端口配置将被忽略:

<cxf:rsServer id="cxfRsConsumer"
              address="http://somehost:1234/path/to/resource"
              serviceClass="org.example.ServiceClass" />
<cxf:cxfEndpoint id="cxfWsConsumer"
                 address="http://somehost:1234/path/to/resource"
                 serviceClass="org.example.ServiceClass" />
[org.wildfly.extension.camel] (pool-2-thread-1) Ignoring configured host: http://somehost:1234/path/to/resource

但是,消费者在默认主机和端口 localhost:8080 或 localhost:8443 上仍然可用。

注意

使用 camel-cxf 使用者 的应用程序必须 打包为 WAR。在以前的 WildFly-Camel 版本中,允许 JAR 等其他类型的存档,但不再受支持。

78.1.1. 配置替代端口

如果要接受替代端口,则必须通过 WildFly 子系统配置它们。这在服务器文档中解释:

https://access.redhat.com/documentation/zh-cn/red_hat_jboss_enterprise_application_platform/7.1/html/configuration_guide/configuring_the_web_server_undertow

78.1.2. 配置 SSL

要配置 SSL,请参阅 WildFly SSL 配置指南:

https://access.redhat.com/documentation/zh-cn/red_hat_jboss_enterprise_application_platform/7.1/html-single/how_to_configure_server_security/#configure_one_way_and_two_way_ssl_tls_for_application

78.1.3. 使用 Elytron 配置安全性

WildFly-Camel 支持使用 Elytron 安全框架保护 camel-cxf 消费者端点。

78.1.3.1. 配置安全域

要使用 Elytron 保护 WildFly-Camel 应用程序,需要在 WAR 部署的 WEB-INF/jboss-web.xml 中引用应用程序安全域:

<jboss-web>
  <security-domain>my-application-security-domain</security-domain>
</jboss-web>

& lt;security-domain& gt; 配置引用 Undertow 子系统定义的 < application-security-domain > 的名称。例如,Undertow 子系统 &lt ;application-security-domain > 在 WildFly 服务器 standalone.xml 配置文件中配置,如下所示:

<subsystem xmlns="urn:jboss:domain:undertow:6.0">
    ...
    <application-security-domains>
        <application-security-domain name="my-application-security-domain" http-authentication-factory="application-http-authentication"/>
    </application-security-domains>
</subsystem>

& lt;http-authentication-factory > application-http-authentication 在 Elytron 子系统中定义。application-http-authentication 默认在 standalone.xmlstandalone-full.xml 服务器配置文件中可用。例如:

<subsystem xmlns="urn:wildfly:elytron:1.2">
    ...
    <http>
        ...
        <http-authentication-factory name="application-http-authentication" http-server-mechanism-factory="global" security-domain="ApplicationDomain">
            <mechanism-configuration>
                <mechanism mechanism-name="BASIC">
                    <mechanism-realm realm-name="Application Realm" />
                </mechanism>
                <mechanism mechanism-name="FORM" />
            </mechanism-configuration>
        </http-authentication-factory>
        <provider-http-server-mechanism-factory name="global" />
    </http>
    ...
</subsystem>

& lt;http-authentication-factory > 名为 application-http-authentication,包含对名为 ApplicationDomain 的 Elytron 安全域的引用。

有关如何配置 Elytron 子系统的更多信息,请参阅 Elytron 文档

78.1.3.2. 配置安全约束、身份验证方法和安全角色

安全约束、camel-cxf 消费者端点的身份验证方法和安全角色可以在 WAR 部署 WEB-INF/web.xml 中配置。例如,配置 BASIC 身份验证:

<web-app>
  <security-constraint>
    <web-resource-collection>
      <web-resource-name>secure</web-resource-name>
      <url-pattern>/webservices/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
      <role-name>my-role</role-name>
    </auth-constraint>
  </security-constraint>
  <security-role>
    <description>The role that is required to log in to /webservices/*</description>
    <role-name>my-role</role-name>
  </security-role>
  <login-config>
    <auth-method>BASIC</auth-method>
    <realm-name>my-realm</realm-name>
  </login-config>
</web-app>

请注意,由 Servlet 规范定义的 <url-pattern > 相对于 web 应用程序的上下文路径。如果您的应用程序被打包为 my-app.war,Wild 将在上下文路径 /my-app 下访问它,< url-patternpattern&gt ; /webservices GovCloud 将应用到相对于 /my-app 的路径。

例如,针对 http://my-server/my-app/webservices/my-endpoint 的请求将与 /webservices netobserv 模式匹配,而 http://my-server/webservices/my-endpoint 不匹配。

这很重要,因为 WildFly-Camel 允许创建 camel-cxf 端点消费者,其基本路径位于主机 Web 应用上下文路径之外。例如,可以为 my-app.war 中的 http://my-server/webservices/my-endpoint 创建 camel-cxf 使用者。

要为此类上下文端点定义安全约束,Wild-Camel 支持自定义非标准 & lt; url-pattern& gt; 约定,其中为带有三个正斜杠 /// 前缀的模式作为服务器主机名。例如,要在 my-app.war 内保护 http://my-server/webservices/my-endpoint,您可以将以下配置添加到 web.xml 中:

<web-app>
  <security-constraint>
    <web-resource-collection>
      <web-resource-name>secure</web-resource-name>
      <url-pattern>///webservices/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
      <role-name>my-role</role-name>
    </auth-constraint>
  </security-constraint>
  <security-role>
    <description>The role that is required to log in to /webservices/*</description>
    <role-name>my-role</role-name>
  </security-role>
  <login-config>
    <auth-method>BASIC</auth-method>
    <realm-name>my-realm</realm-name>
  </login-config>
</web-app>
Red Hat logoGithubRedditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

通过我们的产品和服务,以及可以信赖的内容,帮助红帽用户创新并实现他们的目标。

让开源更具包容性

红帽致力于替换我们的代码、文档和 Web 属性中存在问题的语言。欲了解更多详情,请参阅红帽博客.

關於紅帽

我们提供强化的解决方案,使企业能够更轻松地跨平台和环境(从核心数据中心到网络边缘)工作。

© 2024 Red Hat, Inc.