架构

异常子句

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

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

Exception Clause

你可以在 Java DSL 中使用异常子句(Exception Clause),通过 onException() 方法针对每种异常类型指定所需的错误处理方式。在深入讲解其工作原理之前,我们先给出一个简单的示例。

例如,如果你想在抛出某个特定异常时执行一段特定的处理逻辑,只需这样即可:

  • Java
  • XML
  • YAML
onException(ValidationException.class)
    .to("activemq:validationFailed");

from("seda:inputA")
    .to("validation:foo/bar.xsd", "activemq:someQueue");

from("seda:inputB")
    .to("direct:foo")
    .to("rnc:mySchema.rnc", "activemq:anotherQueue");
<onException>
    <exception>org.apache.camel.ValidationException</exception>
    <to uri="activemq:validationFailed"/>
</onException>

<route>
    <from uri="seda:inputA"/>
    <to uri="validation:foo/bar.xsd"/>
    <to uri="activemq:someQueue"/>
</route>

<route>
    <from uri="seda:inputB"/>
    <to uri="direct:foo"/>
    <to uri="rnc:mySchema.rnc"/>
    <to uri="activemq:anotherQueue"/>
</route>
- onException:
    exception:
      - org.apache.camel.ValidationException
    steps:
      - to:
          uri: activemq:validationFailed
- route:
    from:
      uri: seda:inputA
      steps:
        - to:
            uri: validation:foo/bar.xsd
        - to:
            uri: activemq:someQueue
- route:
    from:
      uri: seda:inputB
      steps:
        - to:
            uri: direct:foo
        - to:
            uri: rnc:mySchema.rnc
        - to:
            uri: activemq:anotherQueue

如果处理 seda:inputA 或 seda:inputB 时抛出 ValidationException(例如由 Validation 组件进行 XSD 校验所导致),那么该消息将被发送到 activemq:validationFailed 队列。

你可以定义多个 onException 子句来实现不同的行为:

  • Java
  • XML
  • YAML
onException(ValidationException.class)
    .to("activemq:validationFailed");

onException(com.foo.ShipOrderException.class)
    .to("activemq:shipFailed");

from("seda:order")
    .to("bean:processOrder");
<onException>
    <exception>org.apache.camel.ValidationException</exception>
    <to uri="activemq:validationFailed"/>
</onException>
<onException>
    <exception>com.foo.ShipOrderException</exception>
    <to uri="activemq:shipFailed"/>
</onException>

<route>
    <from uri="seda:order"/>
    <to uri="bean:processOrder"/>
</route>
- onException:
    exception:
      - org.apache.camel.ValidationException
    steps:
      - to:
          uri: activemq:validationFailed
- onException:
    exception:
      - com.foo.ShipOrderException
    steps:
      - to:
          uri: activemq:shipFailed
- route:
    from:
      uri: seda:order
      steps:
        - to:
            uri: bean:processOrder

作用域

异常子句的作用域分为两类:

  • 全局(对 Java DSL 而言,即每个 RouteBuilder 实例的作用域,用于复用,见下方说明)
  • 或路由特定

其中全局作用域最为简单,也最容易理解。在进阶章节中,我们会深入讲解路由特定的用法,甚至将两者结合使用。不过——

Java DSL 的全局作用域是按 RouteBuilder 实例划分的,因此如果你想在多个 RouteBuilder 类之间共享,可以创建一个抽象的 RouteBuilder 基类,把错误处理逻辑放在它的 configure 方法中。然后让其他类继承该类,并确保调用 super.configure()。这只是在运用 Java 的继承技术。

Camel 如何选择由哪个子句处理抛出的异常?

Camel 使用 DefaultExceptionPolicyStrategy 来决定抛出的异常应由哪个 onException 子句处理。该策略如下:

  • onException 的配置顺序具有优先级。Camel 会按定义的先后顺序(从第一个…到最后一个)依次测试。
  • Camel 会从最底层(嵌套的 caused by)开始,在异常层次结构中逐级向上递归查找,直到找到第一个匹配的 onException 子句。
  • 测试给定异常是否匹配 onException 子句所定义的异常列表时,使用 instanceof 测试。如果存在精确的 instanceof 匹配,则始终采用该匹配;否则,将选择其定义的异常是所抛出异常最近的父类的那个 onException 子句(沿异常层次结构递归向上)。

下面通过一个例子来说明最为清楚:

仅限 Java:异常策略的选择顺序

onException(IOException.class)
    .maximumRedeliveries(3);

onException(OrderFailedException.class)
    .maximumRedeliveries(2);

在上面的示例中,我们定义了两个异常,其中 IOException 位于第一位,因此一旦发生匹配,Camel 就会捕获该异常。也就是说,范围更广的 IOException 会被优先选中。

因此,如果抛出的异常具有如下继承层次:

+ RuntimeCamelException (wrapper exception by Camel)
    + OrderFailedException
        + IOException
            + FileNotFoundException

然后 Camel 将按以下顺序尝试测试异常:FileNotFoundException、IOException、OrderFailedException 和 RuntimeCamelException。由于我们定义了 onException(IOException.class),Camel 会选择它,因为这是最接近的匹配。

如果我们添加第三个带有 FileNotFoundException 的 onException 子句:

仅 Java:添加更具体的异常子句

onException(IOException.class)
    .maximumRedeliveries(3);

onException(OrderFailedException.class)
    .maximumRedeliveries(2);

onException(FileNotFoundException.class)
    .handled(true)
    .to("log:nofile");

接着,在前面的示例中,Camel 将使用最后一个 onException(FileNotFoundException.class),因为它是精确匹配。由于这是精确匹配,它将覆盖之前用于处理同一异常的通用 IOException。

现在考虑一种新情况,如果抛出的是这个异常:

+ RuntimeCamelException (wrapper exception by Camel)
    + OrderFailedException
        + OrderNotFoundException

那么将会选中 onException(OrderFailedException.class)——这一点毫不意外。

下面这个示例演示了 instanceof 测试的特性:当异常是 onException 子句中所定义异常的实例时,Camel 将会选中该子句。示例如下:

+ RuntimeCamelException (wrapper exception by Camel)
    + SocketException

由于 SocketException 是 IOException 的 instanceof,Camel 将选择 onException(IOException.class) 子句。

更多信息

有关特定主题的详细文档,请参阅以下子页面:

  • 重新投递 — 配置重新投递策略、异步延迟重新投递、捕获多个异常
  • 处理模式 — 已处理与继续、使用原始消息、自定义故障处理器
  • 高级用法 — 全局与路由级别、onWhen 谓词、onRedelivery 处理器、自定义策略

评论

登录后参与评论

正在加载评论…