谓词
谓词
表达式与谓词可用于在 DSL 中创建各种企业集成模式,例如基于内容的路由器(Content Based Router)EIP 或收件人列表(Recipient List)EIP。
为了支持动态规则,Camel 使用多种不同的语言,提供了可插拔的 Predicate 策略。
| Simple 语言常被用作 Camel EIP 的谓词和表达式。 |
|---|
谓词 API
Camel 谓词的 API 定义在 org.apache.camel.Predicate 接口中,如下所示:
public interface Predicate {
/**
* Evaluates the predicate on the message exchange and returns true if this
* exchange matches the predicate
*
* @param exchange the message exchange
* @return true if the predicate matches
*/
boolean matches(Exchange exchange);
}Predicate 会被求值为一个布尔值,因此结果只能是 true 或 false。这正是谓词如此强大的原因——它常被用来控制消息的路由,决定消息应当走哪条路径。
一个简单的例子是使用基于内容的路由器 EIP,根据头信息的值来路由 Exchange:
- Java
- XML
- YAML
from("jms:queue:order")
.choice()
.when(header("type").isEqualTo("widget")).to("bean:widgetOrder")
.when(header("type").isEqualTo("wombat")).to("bean:wombatOrder")
.otherwise()
.to("bean:miscOrder")
.end();<route>
<from uri="jms:queue:order"/>
<choice>
<when>
<simple>${header.type} == 'widget'</simple>
<to uri="bean:widgetOrder"/>
</when>
<when>
<simple>${header.type} == 'wombat'</simple>
<to uri="bean:wombatOrder"/>
</when>
<otherwise>
<to uri="bean:miscOrder"/>
</otherwise>
</choice>
</route>- route:
from:
uri: jms:queue:order
steps:
- choice:
when:
- simple: "${header.type} == 'widget'"
steps:
- to:
uri: bean:widgetOrder
- simple: "${header.type} == 'wombat'"
steps:
- to:
uri: bean:wombatOrder
otherwise:
steps:
- to:
uri: bean:miscOrder在上面的路由中,谓词(Predicate) 是 header("type").isEqualTo("widget"),因为它被构建为一个表达式(Expression),并作为谓词(Predicate) 来求值。为此,各种构建器类帮助我们创建简洁流畅的语法。isEqualTo 是一个构建器方法,它根据输入返回一个谓词(Predicate)。
有时候流式构建器会变得很长,阅读起来有点复杂,这时你可以在路由之外定义你的谓词,然后在路由中直接引用该谓词:
Predicate isWidget = header("type").isEqualTo("widget");然后你可以在路由中这样引用它:
纯 Java:在路由中使用谓词变量
from("jms:queue:order")
.choice()
.when(isWidget).to("bean:widgetOrder")
.when(isWombat).to("bean:wombatOrder")
.otherwise()
.to("bean:miscOrder")
.end();对谓词取反
你可以使用 PredicateBuilder 上的 not 方法对谓词取反。
首先,我们导入静态方法 not,这样可以让路由代码简洁易读:
import static org.apache.camel.builder.PredicateBuilder.not;然后,我们就可以像示例中那样,用它包裹现有的谓词并对其取反:
- Java
- XML
- YAML
from("direct:start")
.choice()
.when(not(header("username").regex("goofy|pluto"))).to("mock:people")
.otherwise().to("mock:animals")
.end();<route>
<from uri="direct:start"/>
<choice>
<when>
<simple>${header.username} not regex 'goofy|pluto'</simple>
<to uri="mock:people"/>
</when>
<otherwise>
<to uri="mock:animals"/>
</otherwise>
</choice>
</route>- route:
from:
uri: direct:start
steps:
- choice:
when:
- simple: "${header.username} not regex 'goofy|pluto'"
steps:
- to:
uri: mock:people
otherwise:
steps:
- to:
uri: mock:animals复合谓词
你还可以使用 and、or、not 等布尔运算符以及许多其他运算符来创建复合谓词。
目前,此功能仅在基于 Java 的 DSL 中可用,在其他 DSL(如 XML)中不可用。
借助 PredicateBuilder 类,你可以基于逻辑运算符和比较运算符,将来自不同表达式语言的谓词组合起来:
not、and、orisNull、isNotNullisEqualTo、isGreaterThan、isLessThanstartsWith、endsWithin("X 个谓词中任意一个为真")
此外,使用 PredicateBuilder 还可以创建正则表达式并将其用作谓词,将其应用于表达式的结果,例如
PredicateBuilder.regex(header("foo"), "\d\{4}");正则表达式应用于 foo 头。
也可以组合使用不同的表达式语言,例如:
PredicateBuilder.and(XPathBuilder.xpath("/bookings/flights"), simple("${exchangeProperty.country = 'Spain'}"))下面的示例演示了更多用例:
仅 Java:使用 PredicateBuilder 构建复合谓词
// We define 3 predicates based on some user roles
// we have static imported and/or from org.apache.camel.builder.PredicateBuilder
// First we have a regular user that is just identified having a username header
Predicate user = header("username").isNotNull();
// The admin user must be a user AND have a admin header as true
Predicate admin = and(user, header("admin").isEqualTo("true"));
// And God must be an admin and (either have type god or a special message containing Camel Rider)
Predicate god = and(admin, or(body().contains("Camel Rider"), header("type").isEqualTo("god")));
// As you can see with the predicates above we can stack them to build compound predicates
// In our route below we can create a nice content based router based on the predicates we
// have defined. Then the route is easy to read and understand.
// We encourage you to define complex predicates outside the fluent router builder as
// it will just get a bit complex for humans to read
from("direct:start").choice()
.when(god).to("mock:god")
.when(admin).to("mock:admin")
.when(user).to("mock:user")
.otherwise().to("mock:guest")
.end();评论
登录后参与评论
KnowForge