架构

端点

师成师成· 更新于 2026-09-28· 阅读 26 分钟· 0 次阅读

登录后可跨设备保存划线和私人笔记登录

Camel 通过 Endpoint 接口支持消息端点(Message Endpoint)模式。

端点由组件(Component)创建,并在 DSL 中通过端点 URI 来引用。

示例

下面的示例路由通过 URI 演示了 File 消费端点和 * JMS 生产端点的使用:

  • Java
  • XML
  • YAML
from("file:messages/foo")
    .to("jms:queue:foo");
<route>
    <from uri="file:messages/foo"/>
    <to uri="jms:queue:foo"/>
</route>
- route:
    from:
      uri: file:messages/foo
      steps:
        - to:
            uri: jms:queue:foo

从端点引用 Bean

使用 URI 语法配置端点时,可以通过 #bean:id 表示法引用 Registry 中的 Bean。

仅使用 #id 的旧语法已被废弃,因为 Camel 支持多种以 # 开头的其他函数,会造成歧义。

如果 URI 参数值以 #bean: 开头,Camel 将在 Registry 中按 id 查找指定类型的 Bean。例如:

  • Java
  • XML
  • YAML
from("file:messages/foo?sorter=#bean:mySpecialFileSorter")
    .to("jms:queue:foo");
<route>
    <from uri="file:messages/foo?sorter=#bean:mySpecialFileSorter"/>
    <to uri="jms:queue:foo"/>
</route>
- route:
    from:
      uri: file:messages/foo
      parameters:
        sorter: "#bean:mySpecialFileSorter"
      steps:
        - to:
            uri: jms:queue:foo

将在 Registry 中查找 id 为 mySpecialFileSorter 的 bean。

按类引用 bean

Camel 还支持按类的类型来引用 bean,例如 #class:com.foo.MySpecialSorter,这样将会为给定的类名创建一个新的 bean 实例。

如果需要向构造函数提供参数,这也是可行的(仅限于数字、布尔值、字面量和 null 值)

file://inbox?sorter=#class:com.foo.MySpecialSorter(10, 'Hello world', true)
只有在 Bean 的选项较少、代码易于理解和维护时,才建议内联构造函数参数。另外要注意,如果 Bean 的构造函数被重构,则相应的字符串文本也需要随之更新。

按类型引用 Bean

使用 URI 语法配置端点时,现在可以按类型引用 Bean,系统会根据给定的类型从 Registry 中查找对应的 Bean。

如果在注册表中找到一个该类型的 Bean,则会使用该 Bean 实例;否则将抛出异常。

例如,下面的配置期望 Registry 中存在一个 org.apache.camel.spi.IdempotentRepository 类型的 Bean,文件端点将使用它。

file://inbox?idempontentRepository=#type:org.apache.camel.spi.IdempotentRepository

在 XML 中配置端点 URI(转义 & 符号)

如果你尝试在 XML DSL 中使用 Camel 的某个 URI,并采用 URI 查询参数的写法,例如:

<route>
  <from uri="direct:start?paramA=1&paramB=2"/>
  <to uri="mock:result"/>
</route>

你可能会遇到如下错误……

Caused by: org.xml.sax.SAXParseException: The reference to entity "paramB" must end with the ';' delimiter.
  at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:236)
  at

这是因为在 XML 中,你需要对某些特殊的 XML 字符进行转义,例如:

特殊字符在 XML 中的转义方式
&&amp;
<&lt;
>&gt;

因此,如果你编写如下 XML,它应该可以正常工作……

<route>
  <from uri="direct:start?paramA=1&amp;paramB=2"/>
  <to uri="mock:result"/>
</route>

如果不转义 & 符号,就会抛出 org.xml.sax.SAXParseException 或其他类型的 XML 解析错误。

在用于指定 Camel 端点的 URI 中,& 用于分隔参数。然而,& 同时也是 XML 中的保留字符。

因此,当使用 XML DSL 配置 Camel 路由时,必须将 URI 中的所有 & 替换为 &amp;。

例如,下面是在 Java DSL 和 XML DSL 中的同一个端点 URI,其中 & 已被替换为 &amp;:

  • Java
  • XML
from("timer://myTimer?fixedRate=true&delay=0&period=2000")
<from uri="timer://myTimer?fixedRate=true&amp;delay=0&amp;period=2000"/>

使用原始值(如密码)配置参数值

使用 URI 语法配置端点选项时,参数值默认会进行 URI 编码。如果你希望配置密码并直接原样使用该值而不进行任何编码,这就会成为一个问题。例如,密码中可能包含加号,默认情况下它会被编码为十进制转义。

你可以使用 RAW(value) 语法将参数值定义为原始值,即该值以 RAW( 开头,以右括号 ) 结尾。

下面是一个密码为 se+re?t&23 的小示例:

  • Java
  • XML
  • YAML
  • 展开的 YAML
from("file:inbox")
  .to("ftp:joe@myftpserver.com?password=RAW(se+re?t&23)&binary=true");
<route>
    <from uri="file:inbox"/>
    <to uri="ftp:joe@myftpserver.com?password=RAW(se+re?t&amp;23)&amp;binary=true"/>
</route>
- route:
    from:
      uri: file:inbox
      steps:
        - to:
            uri: ftp:joe@myftpserver.com?password=RAW(se+re?t&23)&binary=true
- route:
    from:
      uri: file
      parameters:
        directoryName: inbox
      steps:
        - to:
            uri: ftp
            parameters:
              host: joe@myftpserver.com
              password: "RAW(se+re?t&23)"
              binary: true

在上面的示例中,我们将密码值声明为 raw,实际密码将按输入的原样使用,例如 se+re?t&23。

当你将 ) 和 & 字符同时用作密码的一部分时(例如 se+re)t&23),可能会遇到一种边界情况。解析器会把 ) 解释为 RAW 函数的结束,并认为后面是一个以 & 开头的参数。在这种情况下,你可以改用 RAW{} 表示法,以便包含 ) 字符并让它作为密码的一部分被解码(例如 RAW{se+re)t&23})。作为一种更安全的替代方案,你也可以使用 password=#property:myPass,然后将 myPass 设置为一个属性占位符值。

在 raw 值中使用环境变量

如果需要使用环境变量,例如作为用户名或密码,现在可以通过在 RAW(…​) 中内联 Simple 语言、使用 $simple{xxx} 语法来实现,如下所示:

  • Java
  • XML
  • YAML
from("file:inbox")
  .to("ftp:joe@myftpserver.com?password=RAW($simple{env:MY_FTP_PASSWORD})&binary=true");
<route>
    <from uri="file:inbox"/>
    <to uri="ftp:joe@myftpserver.com?password=RAW($simple{env:MY_FTP_PASSWORD})&amp;binary=true"/>
</route>
- route:
    from:
      uri: file:inbox
      steps:
        - to:
            uri: ftp:joe@myftpserver.com
            parameters:
              password: "RAW($simple{env:MY_FTP_PASSWORD})"
              binary: true

使用属性占位符的端点 URI

Camel 对属性占位符提供了广泛的支持。

例如,在上面的 ftp 示例中,我们可以将密码外部化到 application.properties 文件中。

myFtpPassword=RAW(se+re?t&23)

随后,Camel 路由即可使用 {{key}} 这种形式来引用该占位符。

  • Java
  • XML
  • YAML
from("file:inbox")
  .to("ftp:joe@myftpserver.com?password={{myFtpPassword}}&binary=true");
<route>
    <from uri="file:inbox"/>
    <to uri="ftp:joe@myftpserver.com?password={{myFtpPassword}}&amp;binary=true"/>
</route>
- route:
    from:
      uri: file:inbox
      steps:
        - to:
            uri: ftp:joe@myftpserver.com
            parameters:
              password: "{{myFtpPassword}}"
              binary: true

并拥有一个包含密码的 application.properties 文件。注意,我们仍然使用 RAW(value) 形式来确保密码被原样使用:

myFtpPassword=RAW(se+re?t&23)

我们仍然可以在 Camel 路由中改用 RAW(value):

仅限 Java:在路由 URI 中内联使用 RAW()

.to("ftp:joe@myftpserver.com?password=RAW({{myFtpPassword}})&binary=true")

接下来,我们需要从属性文件中删除 RAW:

myFtpPassword=se+re?t&23

配置 CamelContext 默认缓存大小

CamelContext 默认会缓存最近使用的 1000 个端点(基于 LRUCache)。

必须在 CamelContext 上将其作为全局选项进行配置,如下方 Java 代码所示:

仅使用 Java:通过 CamelContext API 配置端点缓存大小

getCamelContext().getGlobalOptions().put(Exchange.MAXIMUM_ENDPOINT_CACHE_SIZE, "500");

默认的最大缓存大小为 1000。

你需要在 CamelContext 启动之前完成此配置。

使用时、分语法配置时间间隔

Camel 的一些组件提供了用于指定时间间隔的选项,该时间间隔必须以毫秒为单位输入。

当数值较大时,例如 2700000 毫秒(45 分钟),这对人类阅读来说并不友好。

在 Camel 中,你可以使用更具可读性的语法来配置,说明如下:

语法单位
h小时
m分钟
s秒

例如,Timer 端点可以按如下方式配置:

  • Java
  • XML
  • YAML
from("timer:foo?period=45m").to("log:foo");
<route>
    <from uri="timer:foo?period=45m"/>
    <to uri="log:foo"/>
</route>
- route:
    from:
      uri: timer:foo?period=45m
      steps:
        - to:
            uri: log:foo

你可以混合搭配这些单位,因此也可以这样写:

  • Java
  • XML
  • YAML
from("timer:foo?period=1h15m").to("log:foo");
from("timer:bar?period=2h30s").to("log:bar");
from("timer:bar?period=3h45m58s").to("log:bar");
<route>
    <from uri="timer:foo?period=1h15m"/>
    <to uri="log:foo"/>
</route>

<route>
    <from uri="timer:bar?period=2h30s"/>
    <to uri="log:bar"/>
</route>

<route>
    <from uri="timer:bar?period=3h45m58s"/>
    <to uri="log:bar"/>
</route>
- route:
    from:
      uri: timer:foo?period=1h15m
      steps:
        - to:
            uri: log:foo
- route:
    from:
      uri: timer:bar?period=2h30s
      steps:
        - to:
            uri: log:bar
- route:
    from:
      uri: timer:bar?period=3h45m58s
      steps:
        - to:
            uri: log:bar

不过,你也可以使用长语法:

语法单位
hour 或 hours小时
minute 或 minutes分钟
second 或 seconds秒
  • Java
  • XML
  • YAML
from("timer:foo?period=45minutes").to("log:foo");
<route>
    <from uri="timer:foo?period=45minutes"/>
    <to uri="log:foo"/>
</route>
- route:
    from:
      uri: timer:foo?period=45minutes
      steps:
        - to:
            uri: log:foo

Java Endpoint API

你几乎从不需要通过 Java API 手动创建端点。

通过 Endpoint,你可以使用以下 Java API 方法为该端点创建生产者或消费者:

评论

登录后参与评论

正在加载评论…