如果您要监视,调试,排除流经路由的消息并对其进行故障排除,而又不必从通道中永久消耗消息,那么您就需要使用电线。
有线分流器充当收件人列表,该收件人列表从输入通道中消费消息并将其发布到两个输出通道。
第一个是作为主要通道的实际目的地,第二个是作为次要通道的电线接头目的地。
在开始示例之前,让我们研究一下设置细节。
本示例使用以下框架:
依存关系
我们仅依赖骆驼的核心组件和记录器组件,因此我们的pom.xml
包含:
-
camel-core
-
slf4j-api
-
slf4j-log4j12
pom.xml:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.javarticles.camel</groupId>
<artifactId>camelHelloWorld</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-core</artifactId>
<version>2.15.1</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.12</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.12</version>
</dependency>
</dependencies>
</project>
简单的丝锥示例
窃听器接收消息,复制消息并将其发送到窃听器目的地。 原始交换继续通过路线到达实际目的地。 骆驼不等待来自丝锥的响应,因为丝锥将消息交换模式(MEP)设置为InOnly。
您需要使用wireTap
语句,指定将消息副本发送到何处的端点URI。 Wire Tap处理器在由Camel路由引擎管理的单独线程上对其进行处理。
在我们的示例中,我们发送一条消息“ One”,以进行direct:start
以启动路线。 消息的副本将发送到wireTap目的地direct:tap
。 原始消息消息在通往bean
的主路径中继续进行进一步处理。 MyBean.addTwo
将“ Two”字符串添加到“ One”。 在发生在单独线程中的窃听路由中,消息将发送到MyBean.addThree
以将“ Three”添加到“ One”。
CamelWiretap示例:
package com.javarticles.camel;
import org.apache.camel.CamelContext;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.impl.DefaultCamelContext;
import org.apache.camel.util.jndi.JndiContext;
public class CamelWiretapExample {
public static final void main(String[] args) throws Exception {
JndiContext jndiContext = new JndiContext();
jndiContext.bind("myBean", new MyBean());
CamelContext camelContext = new DefaultCamelContext(jndiContext);
try {
camelContext.addRoutes(new RouteBuilder() {
public void configure() {
from("direct:start")
.log("Main route: Send '${body}' to tap router")
.wireTap("direct:tap")
.log("Main route: Add 'two' to '${body}'")
.bean(MyBean.class, "addTwo")
.log("Main route: Output '${body}'");
from("direct:tap")
.log("Tap Wire route: received '${body}'")
.log("Tap Wire route: Add 'three' to '${body}'")
.bean(MyBean.class, "addThree")
.log("Tap Wire route: Output '${body}'");
}
});
ProducerTemplate template = camelContext.createProducerTemplate();
camelContext.start();
template.sendBody("direct:start", "One");
} finally {
camelContext.stop();
}
}
}
MyBean:
package com.javarticles.camel;
import java.util.ArrayList;
import java.util.List;
public class MyBean {
public String addTwo(String body) {
return body + " and two";
}
public String addThree(String body) {
return body + " and three";
}
}
主路线最终输出为“一和二”。 电线分接目标输出为“一和三”。
输出:
12:19| INFO | MarkerIgnoringBase.java 95 | Main route: Send 'One' to tap router
12:19| INFO | MarkerIgnoringBase.java 95 | Main route: Add 'two' to 'One'
12:19| INFO | MarkerIgnoringBase.java 95 | Tap Wire route: received 'One'
12:19| INFO | MarkerIgnoringBase.java 95 | Tap Wire route: Add 'three' to 'One'
12:19| INFO | MarkerIgnoringBase.java 95 | Tap Wire route: Output 'One and three'
12:19| INFO | MarkerIgnoringBase.java 95 | Main route: Output 'One and two'
将消息浅复制到Wire Tap
默认情况下,Wire Tap处理器对Camel Exchange实例进行浅表复制。 交换的副本将发送到wireTap语句中指定的端点。 窃听消息的正文包含与原始消息相同的对象,这意味着在窃听路由期间对该对象内部状态的任何更改也可能最终会更改主消息的正文。
在下面的示例中,我们没有将字符串“ One”发送,而是将其包装在MyPayload
对象中,然后将其发送到direct:start
以启动路由。 主路径将有效负载的值附加“二”,同样,电线路径附加“三”。
MyBean:
package com.javarticles.camel;
import java.util.ArrayList;
import java.util.List;
public class MyBean {
public String addTwo(String body) {
return body + " and two";
}
public String addThree(String body) {
return body + " and three";
}
public MyPayload addTwo(MyPayload body) {
body.setValue(body.getValue() + " and two");
return body;
}
public MyPayload addThree(MyPayload body) {
body.setValue(body.getValue() + " and three");
return body;
}
}
MyPayload
充当包含字符串值的包装对象。
MyPayload:
package com.javarticles.camel;
public class MyPayload {
private String value;
public MyPayload(String value) {
this.value = value;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String toString() {
return value;
}
}
即使将消息复制到丝锥目标的事件,其持有的对象也与主要路线的对象相同。 由于电线分路布线是同时发生的,因此有可能改变主布线的信息。
CamelWiretapShallowCopy示例:
package com.javarticles.camel;
import org.apache.camel.CamelContext;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.impl.DefaultCamelContext;
import org.apache.camel.util.jndi.JndiContext;
public class CamelWiretapShallowCopyExample {
public static final void main(String[] args) throws Exception {
JndiContext jndiContext = new JndiContext();
jndiContext.bind("myBean", new MyBean());
CamelContext camelContext = new DefaultCamelContext(jndiContext);
try {
camelContext.addRoutes(new RouteBuilder() {
public void configure() {
from("direct:start")
.log("Main route: Send '${body}' to tap router")
.wireTap("direct:tap")
.log("Main route: Add 'two' to '${body}'")
.bean(MyBean.class, "addTwo")
.log("Main route: Output '${body}'");
from("direct:tap")
.log("Tap Wire route: received '${body}'")
.log("Tap Wire route: Add 'three' to '${body}'")
.bean(MyBean.class, "addThree")
.log("Tap Wire route: Output '${body}'");
}
});
ProducerTemplate template = camelContext.createProducerTemplate();
camelContext.start();
MyPayload payload = new MyPayload("One");
template.sendBody("direct:start", payload);
System.out.println("Final payload: " + payload.getValue());
} finally {
camelContext.stop();
}
}
}
最终的有效负载已损坏,它是“一个和三个”而不是“一个和两个”。 在下一部分中,我们将深度复制对象,然后再将其传递到丝锥目标位置。
输出:
15:25| INFO | MarkerIgnoringBase.java 95 | Main route: Send 'One' to tap router
15:25| INFO | MarkerIgnoringBase.java 95 | Main route: Add 'two' to 'One'
15:25| INFO | MarkerIgnoringBase.java 95 | Tap Wire route: received 'One'
15:25| INFO | MarkerIgnoringBase.java 95 | Tap Wire route: Add 'three' to 'One'
15:25| INFO | MarkerIgnoringBase.java 95 | Tap Wire route: Output 'One and three'
15:25| INFO | MarkerIgnoringBase.java 95 | Main route: Output 'One and three'
Final payload: One and three
15:25| INFO | DefaultCamelContext.java 2660 | Apache Camel 2.15.1 (CamelCont
消息的深层复制到Wire Tap
Wire Tap EIP为我们提供了一种执行消息的“深层”副本的机制。
首先让我们向MyPayload
添加深度克隆方法。
MyPayload:
package com.javarticles.camel;
public class MyPayload {
private String value;
public MyPayload(String value) {
this.value = value;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String toString() {
return value;
}
public MyPayload deepClone() {
MyPayload myPayload = new MyPayload(value);
return myPayload;
}
}
接下来,实现一个自定义Processor
以深度克隆MyPayload
对象。
MyPayloadClonePrepare:
package com.javarticles.camel;
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
public class MyPayloadClonePrepare implements Processor {
public void process(Exchange exchange) throws Exception {
MyPayload myPayload = exchange.getIn().getBody(MyPayload.class);
exchange.getIn().setBody(myPayload.deepClone());
}
}
需要在onPrepare
之后wireTap
使用onPrepare
语句调用此方法。
CamelWiretapOnPrepare示例:
package com.javarticles.camel;
import org.apache.camel.CamelContext;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.impl.DefaultCamelContext;
import org.apache.camel.util.jndi.JndiContext;
public class CamelWiretapOnPrepareExample {
public static final void main(String[] args) throws Exception {
JndiContext jndiContext = new JndiContext();
jndiContext.bind("myBean", new MyBean());
CamelContext camelContext = new DefaultCamelContext(jndiContext);
try {
camelContext.addRoutes(new RouteBuilder() {
public void configure() {
from("direct:start")
.log("Send '${body}' to tap router")
.wireTap("direct:tap")
.onPrepare(new MyPayloadClonePrepare())
.end()
.delay(1000)
.log("Output of main '${body}'");
from("direct:tap")
.log("Tap router received '${body}'")
.bean(MyBean.class, "addThree")
.log("Output of tap '${body}'");
}
});
ProducerTemplate template = camelContext.createProducerTemplate();
camelContext.start();
MyPayload payload = new MyPayload("One");
template.sendBody("direct:start", payload);
System.out.println("Final payload: " + payload.getValue());
} finally {
camelContext.stop();
}
}
}
现在,主路径的输出不受拉线的路径影响。 它正确显示为“一个和两个”。
输出:
18:46| INFO | MarkerIgnoringBase.java 95 | Send 'One' to tap router
18:46| INFO | MarkerIgnoringBase.java 95 | Tap router received 'One'
18:46| INFO | MarkerIgnoringBase.java 95 | Output of tap 'One and three'
18:46| INFO | MarkerIgnoringBase.java 95 | Output of main 'One'
Final payload: One
下载源代码
这是有关Apache Camel Wire Tap的示例。 您可以在此处下载源代码: camelWireTapExample.zip
翻译自: https://www.javacodegeeks.com/2015/05/apache-camel-wire-tap-examples.html