7

ルートの最後でリクエストメッセージとレスポンスメッセージの両方を処理したいと思います。ただし、元のリクエストメッセージにアクセスする方法がわかりません。

私はいくつかの基本的な概念に苦労しているというひどい気持ちを持っています。

これが私の問題の概要を説明するDSLの簡単なルート例です(streamCachingはコンテキスト全体で有効になっています):

from("activemq:queue:myQueue")
.to("log:" + getClass().getName() + "?showOut=true")
.to("http://localhost:8080/someBackend")
.log("Now in.Body returns this: ${in.body} and out.Body this: ${out.body}")
.to("log:" + getClass().getName() + "?showOut=true");

これが私のログからの抜粋です(読みやすくするために改行を編集しました)。ご覧のとおり、httpサーバーが応答すると元のSOAPメッセージは失われ、SOAP応答オブジェクトはメッセージのinBodyに格納されます。

2012-09-25 17:28:08,312 local.bar.foo.MyRouteBuilder INFO - 
    Exchange[ExchangePattern:InOut, BodyType:byte[],
    Body:<?xml version="1.0" encoding="UTF-8"?><env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"><env:Header /><env:Body><urn:someRequest  xmlns:urn="http://foo.bar.local/ns"></urn:someRequest></env:Body></env:Envelope>, 
    Out: null]
2012-09-25 17:28:08,398 org.apache.camel.component.http.HttpProducer DEBUG - 
    Executing http POST method: http://localhost:8080/someBackend
2012-09-25 17:28:09,389 org.apache.camel.component.http.HttpProducer DEBUG - 
    Http responseCode: 200
2012-09-25 17:28:09,392 route2 INFO - 
    Now in.Body returns this: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns2:someResponse xmlns:ns2="http://foo.bar.local/ns"</ns2:someResponse></soap:Body></soap:Envelope>
    and out.Body this: 
2012-09-25 17:28:09,392 local.bar.foo.MyRouteBuilder INFO - 
    Exchange[ExchangePattern:InOut,  
    BodyType:org.apache.camel.converter.stream.InputStreamCache,
    Body:[Body is instance of org.apache.camel.StreamCache],
    Out: null]

ルート全体でin.bodyとout.bodyが保持されることを期待していましたか?

私が検討している代替ソリューション:

  • 相関識別子パターンを使用して、要求と応答の両方を相関させます。しかし、これはメッセージ本文も保持しますか?また、私のリクエスト/リプライメッセージには、相関のための一意の識別子がありません。
  • httpバックエンドへの呼び出しを実行し、要求オブジェクトと応答オブジェクトの両方を処理するカスタムBeanを記述します(ただし、これは基本的にCamelを使用しないソリューションであり、車輪の再発明であるため、推奨されません)

すでに失敗したアプローチ:

ルートの最後に次のようなプロセッサを使用して元の要求メッセージにアクセスしようとしましたが、成功しませんでした。

 process(new Processor() {
   @Override
   public void process(Exchange exchange) throws Exception {
      Message originalInMessage = exchange.getUnitOfWork().getOriginalInMessage();
         logger.debug(originalInMessage.getBody(String.class));
         logger.debug(exchange.getIn().getBody(String.class));
   }
 });

助けてくれてありがとう

4

4 に答える 4

14

inメッセージの元の本文をヘッダーまたはプロパティに格納し、最後に取得するだけです。

from("activemq:queue:myQueue")
.setProperty("origInBody", body())
.to("http://localhost:8080/someBackend")

http呼び出しの後、プロパティorigInBodyにアクセスできます。

于 2012-09-26T06:04:08.550 に答える
13

まず、この記事では、ラクダの出入りがどのように機能するかを非常によく示しています:http: //camel.apache.org/using-getin-or-getout-methods-on-exchange.html

通常、outメッセージは常に使用されるわけではなく、各ステップでinメッセージからコピーされます。

あなたの場合、元のメッセージをルートの終わりまで残しておきたい場合は、エンリッチメントEIPを使用できます。http://camel.apache.org/content-enricher.html

ルートは次のようになります。

public class MyAggregationStrategy implements AggregationStrategy {
  public Exchange aggregate(Exchange orig, Exchange httpExchange){
    // if you want to check something with the Http request, you better do that here 
    if( httpExchange is not correct in some way ) 
       throw new RuntimeException("Something went wrong");

    return orig;
  }
}

AggregationStrategy aggStrategy = new MyAggregationStrategy();

from("activemq:queue:myQueue")
  .enrich("http://localhost:8080/someBackend",aggStrategy)
  .//keep processing the original request here if you like, in the "in" message
于 2012-09-25T19:52:15.480 に答える
5

ラクダの最大の問題の1つは、それを誤用しやすいことです。これを正しく使用する最良の方法は、EIPの観点から考えることです。ラクダの主な目標の1つは、DSLにEIPを実装することです。

これがEIPのリストです

今それについて考えてください。最後にリクエストとレスポンスが必要ですが、どのような用途に使用しますか?ロギング、アグリゲーション、...?ロギングの場合、correlationIdで十分であるため、requestとproxied-responseの両方に基づいて応答を作成するためにcorrelationIdが必要であると思います。それがあなたが望むものなら、あなたは次のようなことをすることができます

from("direct:receiveRequest")
   .enrich("direct:proxyResponse", new RequestAndResponseAggregationStrategy())

リクエスト(oldExchangeの場合)とレスポンス(newExchangeの場合)をマージする機会があります。

クリスチャンシュナイダーに敬意を表して、後で再利用できるプロパティにリクエストを入れるというアイデアは悪いデザインだと思います。そうすることで、ルート間に副作用が生じます。あなたのルートが別のルートのサブルートである場合、おそらくそれらのプロパティを消去します。後で元に戻すために保存する場合は、次のようなことを行う必要があります。

from("direct:receiveRequest")
    .enrich("direct:subRouteToIgnoreResponse", AggregationStrategies.useOriginal())

私が何度もやった本当に本当に悪いデザインはやることです:

from("direct:receiveRequest")
    .to("direct:subroute")

from("direct:subroute")
    .setProperty("originalBody", body())
    .to("direct:handling")
    .transform(property("originalBody")

これは「プロパティ/ヘッダー地獄」につながり、プロセッサの単なる連続呼び出しであるルートにつながります。

また、EIPの問題の解決策が思いつかない場合は、ラクダを使用してコンポーネントにアクセスする必要があります。たとえば、次のようなものです。

from("http://api.com/services")
   .to(new SomeNotTranslatableToEIPProcessor())
   .to("ftp://destination")

ただし、これらのコンポーネントには独自の目標があることを忘れないでください。類似した動作間で共通の抽象化を作成することです(たとえば、時間ベースのポーリングコンシューマー)。非常に特定のニーズがある場合、ラクダのコンポーネントをこの特定のニーズに合わせて曲げようとすると、コードの巨大なチャンクが簡単に保守できなくなる可能性があります。

キャメルをゴールデンハンマーのアンチパターンにしないでください

于 2018-07-19T12:16:11.913 に答える
0

私はよく集計戦略を使用します。これは古い交換を保持し、エンリッチの結果をヘッダーに入れます。

import org.apache.camel.Exchange;
import org.apache.camel.processor.aggregate.AggregationStrategy;

public class SetBodyToHeaderAggregationStrategy implements AggregationStrategy {

    private String headerName = "newBody";

    public Exchange aggregate(Exchange oldExchange, Exchange newExchange) {
        oldExchange.getIn().setHeader(headerName, newExchange.getIn().getBody());

        return oldExchange;
    }

    @SuppressWarnings("unused")
    public void setHeaderName(String headerName) {
        this.headerName = headerName;
    }

}

これで、次のように使用できます。

<enrich strategyRef="setBodyToHeaderAggregationStrategy">
  <constant>dosomething</constant>
</enrich>

<log loggingLevel="INFO" message="Result body from enrich: ${header.newBody}. Original body: ${body}" loggerRef="log"/>
于 2019-05-13T13:54:45.787 に答える