关于java:Apache Camel CXF端点空回复

Apache Camel CXF endpoint null reply

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<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控制台类来测试路由

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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();

}

期望控制台日志应该显示

1
"Received reply from orderEndpoint = OK"

但是,我得到了

1
"Received reply from orderEndpoint = null"

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

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

这意味着 Web 服务应该已生成回复消息"OK",但我不确定为什么此回复消息没有作为 requestBody() 方法调用的返回值结转...

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

想看看有没有人能提供一些线索。

--- 编辑 1 ---

我已经更新了路线定义,只保留了如下路线

1
2
3
4
5
6
7
    <route>
        <from uri="cxf:bean:orderEndpoint" />
        <transform>
            <constant>OK</constant>
        </transform>
        <to uri="seda:incomingOrders" />
    </route>

并更新了main方法

1
2
3
4
    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);

但是,它因超时异常而失败

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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$1.asyncInvoke(CxfConsumer.java:95)
at org.apache.camel.component.cxf.CxfConsumer$1.invoke(CxfConsumer.java:75)
at org.apache.cxf.interceptor.ServiceInvokerInterceptor$1.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$2.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$2.run(AbstractConnection.java:540)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:635)
at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:555)
at java.lang.Thread.run(Thread.java:745)

您正在请求 CXF 端点的正文。如果您查看您的路线,您可以看到您在转换标记中设置了正文的内容,该标记位于路线定义的后面。因此,由于 requestBody() 的结果,您没有得到 OK 是合乎逻辑的。这同样适用于您的 seda 端点。我敢打赌 orderEndpoint_MsgIn 的 Logged 正文与 OK 不同。

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

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

1
2
3
4
5
6
7
<route>
    <from uri="cxf:bean:orderEndpoint" />
    <transform>
        <constant>OK</constant>
    </transform>
    <wireTap uri="seda:incomingOrders" />
</route>

并将 ConsumerTemplate 与 seda 端点一起使用:

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

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

有关使用 wireTap 而不是 to 的说明,请参阅这篇文章