Apache Camel CXF 端点空回复

Apache Camel CXF endpoint null reply

我按照 Camel in Action 书的第 7 章实现了 CXF 路线。

<cxf:cxfEndpoint 
    id="orderEndpoint" 
    address="http://localhost:9000/order/"
    serviceClass="test.order.OrderEndpoint" 
    wsdlURL="wsdl/order.wsdl" />


<camelContext xmlns="http://camel.apache.org/schema/spring">
    <route>
        <!-- Expose route as web service endpoint -->
        <from uri="cxf:bean:orderEndpoint" />
        <to uri="log:orderEndpoint_MsgIn" />
        <to uri="seda:incomingOrders" />
        <transform>
            <constant>OK</constant>
        </transform>
        <to uri="log:orderEndpoint_MsgOut" />
    </route>

    <!-- test route -->
    <route>
        <from uri="seda:incomingOrders" />
        <to uri="mock:end" />
    </route>
</camelContext>

然后我实现了一个java控制台class来测试路由

public static void main(String[] args) throws Exception{
    Main main = new Main(); 
    AbstractApplicationContext context = new ClassPathXmlApplicationContext(
            "META-INF/spring/cxfWsComponentTestContext.xml"
            );

    main.setApplicationContext(context);

    main.start();
    ProducerTemplate producer = main.getCamelTemplate();

    List<Object> params = new ArrayList<Object>();
    params.add("motor");
    params.add(1);
    params.add("honda");

    String reply = producer.requestBody("cxf:bean:orderEndpoint", params, String.class);
    LOG.info("Received reply from orderEndpoint = " + reply);

    Thread.sleep(10000);

    main.stop();

} 

预计控制台日志应显示

"Received reply from orderEndpoint = OK"

然而,我得到了

"Received reply from orderEndpoint = null" 

在控制台日志中我可以看到条目

"orderEndpoint_MsgOut           INFO  Exchange[ExchangePattern: InOut, BodyType: String, Body: OK]"

这意味着 Web 服务应该已经生成了回复消息 "OK",但我不确定为什么这个回复消息没有作为 requestBody() 方法的 return 值继续存在打电话...

我下载了 Camel in Action 第 7 章的示例代码和 运行 Junit 测试用例,它能够 return 结果符合预期...我尝试比较路由定义和源代码与我的代码,但到目前为止无法发现任何差异...

想看看是否有人可以提供一些线索。

--- 编辑 1 ---

我更新了路由定义,只保留如下路由

    <route>
        <from uri="cxf:bean:orderEndpoint" />
        <transform>
            <constant>OK</constant>
        </transform>
        <to uri="seda:incomingOrders" />
    </route>

并更新了主要方法

    producer.requestBody("cxf:bean:orderEndpoint", params, String.class);
    ConsumerTemplate consumer = producer.getCamelContext().createConsumerTemplate();
    Exchange reply = consumer.receive("seda:incomingOrders");
    LOG.info("Received reply from seda:incomingOrders = " + reply);

然而,它因超时异常而失败

org.apache.camel.ExchangeTimedOutException: The OUT message was not received within: 30000 millis. Exchange[Message: OK]
at org.apache.camel.component.seda.SedaProducer.process(SedaProducer.java:144)
at org.apache.camel.processor.SendProcessor.process(SendProcessor.java:129)
at org.apache.camel.management.InstrumentationProcessor.process(InstrumentationProcessor.java:77)
at org.apache.camel.processor.RedeliveryErrorHandler.process(RedeliveryErrorHandler.java:448)
at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:191)
at org.apache.camel.processor.Pipeline.process(Pipeline.java:118)
at org.apache.camel.processor.Pipeline.process(Pipeline.java:80)
at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:191)
at org.apache.camel.component.cxf.CxfConsumer.asyncInvoke(CxfConsumer.java:95)
at org.apache.camel.component.cxf.CxfConsumer.invoke(CxfConsumer.java:75)
at org.apache.cxf.interceptor.ServiceInvokerInterceptor.run(ServiceInvokerInterceptor.java:59)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at org.apache.cxf.interceptor.ServiceInvokerInterceptor.run(ServiceInvokerInterceptor.java:126)
at org.apache.cxf.workqueue.SynchronousExecutor.execute(SynchronousExecutor.java:37)
at org.apache.cxf.interceptor.ServiceInvokerInterceptor.handleMessage(ServiceInvokerInterceptor.java:131)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:308)
at org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:121)
at org.apache.cxf.transport.http.AbstractHTTPDestination.invoke(AbstractHTTPDestination.java:251)
at org.apache.cxf.transport.http_jetty.JettyHTTPDestination.doService(JettyHTTPDestination.java:234)
at org.apache.cxf.transport.http_jetty.JettyHTTPHandler.handle(JettyHTTPHandler.java:70)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1129)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1065)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:215)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97)
at org.eclipse.jetty.server.Server.handle(Server.java:497)
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:310)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:257)
at org.eclipse.jetty.io.AbstractConnection.run(AbstractConnection.java:540)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:635)
at org.eclipse.jetty.util.thread.QueuedThreadPool.run(QueuedThreadPool.java:555)
at java.lang.Thread.run(Thread.java:745)

您正在请求 CXF 端点的正文。如果您查看您的路线,您会发现您在路线定义之后的转换标记中设置了正文的内容。因此,您因 requestBody() 而无法正常工作是合乎逻辑的。这同样适用于您的 seda 端点。我敢打赌 orderEndpoint_MsgIn 的 Logged 正文与 OK 不同。

关于您在 orderEndpoint_MsgOut 处的日志是正确的,这是因为您在转换步骤之后记录了正文。

为了收到OK,可以使用这条路线:

<route>
    <from uri="cxf:bean:orderEndpoint" />
    <transform>
        <constant>OK</constant>
    </transform>
    <wireTap uri="seda:incomingOrders" />
</route>

并使用 ConsumerTemplate 和 seda 端点:

ConsumerTemplate consumer = producer.getCamelContext().createConsumerTemplate();
String reply = consumer.receive("seda:incomingOrders");
LOG.info("Received reply from seda = " + reply);

您应该在 requestBody()main.stop() 之间使用此代码。

有关使用 wireTap 而不是 to 的解释,请参阅此 post