搜索

2.3. 异常处理

download PDF

摘要

Apache Camel 提供了几种不同的机制,它们可让您以不同的粒度处理异常:您可以使用 doTrydoCatchdoFinally ;或者,您可以指定每个异常类型采取什么操作,并使用 onException 将其此规则应用到 RouteBuilder 中的所有路由;或者,您可以指定 执行所有 异常类型的操作,并使用 Handler 错误处理程序中的所有路由。

有关异常处理的详情,请参考 第 6.3 节 “死信频道”

2.3.1. onException Clause

概述

onException 子句是一种在一个或多个路由中捕获异常的强大机制:它特定于类型,允许您定义不同的操作来处理不同的异常类型;它允许您使用基本上(实际上,稍微扩展的)语法定义为路由,以便您以处理异常的方式进行大量操作。

使用 onException 捕获异常

onException 子句是 trapping 的机制,而不是捕获异常。也就是说,一旦定义了 onException 子句,它会捕获路由中任何时间点上出现的异常。这与 Java try/catch 机制(其中异常被发现)相反,只有在特定代码片段 被明确 包含在尝试块中时。

当您定义 onException 子句时,Apache Camel 运行时隐式将每个路由节点包含在尝试块中时会出现什么情况。这就是为什么 onException 子句可以在路由中的任何点上捕获异常。但会自动为您完成这一换行;它在路由定义中不可见。

Java DSL 示例

在以下 Java DSL 示例中,onException 子句应用到 RouteBuilder 类中定义的所有路由。如果在处理任一路由(from ("seda:inputA")from ("seda:inputB")时发生 ValidationException 异常,则 onException 子句会捕获异常并将当前交换重定向到 validationFailed JMS 队列(充当死信队列)。

// Java
public class MyRouteBuilder extends RouteBuilder {

  public void configure() {
    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");
  }
}

XML DSL 示例

前面的示例也可以在 XML DSL 中表达,使用 onException 元素来定义 exception 子句,如下所示:

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:camel="http://camel.apache.org/schema/spring"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
    http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">

    <camelContext xmlns="http://camel.apache.org/schema/spring">
        <onException>
            <exception>com.mycompany.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="rnc:mySchema.rnc"/>
            <to uri="activemq:anotherQueue"/>
        </route>
    </camelContext>

</beans>

陷阱多个例外

您可以在 RouteBuilder 范围内定义多个 onException 子句来陷阱异常。这可让您采取不同的操作来响应不同的异常。例如,Java DSL 中定义的以下一系列 onException 子句为 ValidationExceptionIOExceptionException 定义不同的 deadletter目的地:

onException(ValidationException.class).to("activemq:validationFailed");
onException(java.io.IOException.class).to("activemq:ioExceptions");
onException(Exception.class).to("activemq:exceptions");

您可以在 XML DSL 中定义同一一系列 onException 子句,如下所示:

<onException>
    <exception>com.mycompany.ValidationException</exception>
    <to uri="activemq:validationFailed"/>
</onException>
<onException>
    <exception>java.io.IOException</exception>
    <to uri="activemq:ioExceptions"/>
</onException>
<onException>
    <exception>java.lang.Exception</exception>
    <to uri="activemq:exceptions"/>
</onException>

您还可以将多个例外分组在一起,以便由同一 onException 子句捕获。在 Java DSL 中,您可以按如下方式对多个例外进行分组:

onException(ValidationException.class, BuesinessException.class)
  .to("activemq:validationFailed");

在 XML DSL 中,您可以通过在 onException 元素中定义多个 例外元素来对多个例外 进行分组,如下所示:

<onException>
    <exception>com.mycompany.ValidationException</exception>
    <exception>com.mycompany.BuesinessException</exception>
    <to uri="activemq:validationFailed"/>
</onException>

当捕获多个异常时,onException 子句的顺序非常重要。Apache Camel 最初会尝试将抛出的异常 与第一个 子句匹配。如果第一个子句无法匹配,则尝试下一个 onException 子句,直到找到匹配项为止。每个匹配尝试都受到以下算法的管控:

  1. 如果抛出的异常是 串联的异常 (即,异常被误认为是不同的例外),则最嵌套的异常类型最初是匹配的基础。这个例外被测试如下:

    1. 如果 exception-to-test 具有在 onException 子句中指定的类型(使用 instanceof测试),则会触发匹配项。
    2. 如果 exception-to-test 是 onException 子句中指定的类型的子类型,则会触发匹配项。
  2. 如果最嵌套的异常无法产生匹配项,则改为测试链(嵌套异常)中的下一个异常。测试继续进行链,直到触发了匹配项或链已耗尽为止。
注意

throwException EIP 可让您从简单语言表达式创建新异常实例。您可以根据当前交换中的可用信息使其动态化,例如:

<throwException exceptionType="java.lang.IllegalArgumentException" message="${body}"/>

Deadletter 频道

目前,onException 使用的基本示例都利用了 deadletter 频道 模式。也就是说,当一个 onException 子句捕获异常时,当前的交换会被路由到一个特殊的目的地( deadletter 频道)。deadletter 频道充当 尚未 处理的失败消息的冻结区域。管理员可以稍后检查消息,并决定需要采取什么操作。

有关 deadletter 频道模式的详情,请参考 第 6.3 节 “死信频道”

使用原始消息

在路由中间出现异常时,交换中的消息可能会大大修改(即使人可读也是如此)。通常,如果死信队列中的消息是 原始消息,则管理员更容易决定要采取的纠正性操作。默认情况下,useOriginalMessage 选项为 false,但如果它在错误处理程序上配置了,则会自动启用。

注意

当应用到将消息发送到多个端点的 Camel 路由或将消息分成部分时,useOriginalMessage 选项可能会导致意外行为。原始消息可能无法在 Multicast、Splitter 或 RecipientList 路由中保留,在其中修改原始消息。

在 Java DSL 中,您可以将交换中的消息替换为原始消息。将 setAllowUseOriginalMessage () 设置为 true,然后使用 useOriginalMessage () DSL 命令,如下所示:

onException(ValidationException.class)
  .useOriginalMessage()
  .to("activemq:validationFailed");

在 XML DSL 中,您可以通过对 onException 元素设置 useOriginalMessage 属性来检索原始消息,如下所示:

<onException useOriginalMessage="true">
    <exception>com.mycompany.ValidationException</exception>
    <to uri="activemq:validationFailed"/>
</onException>
注意

如果 setAllowUseOriginalMessage () 选项设为 true,Camel 会在路由开始时生成原始消息的副本,这样可确保在您调用 useOriginalMessage () 时原始消息可用。但是,如果 Camel 上下文上的 setAllowUseOriginalMessage () 选项被设置为 false (这是默认设置 ), 则无法访问原始消息,您无法调用 useOriginalMessage ()

利用默认行为的原因是在处理大量消息时优化性能。

在 2.18 之前的 Camel 版本中,allowUseOriginalMessage 的默认设置是 true。

重新发送策略

Apache Camel 不会中断消息的处理,并在引发异常时立即放弃,而是为您提供尝试在异常发生时对消息进行 恢复 的选项。在联网系统中,可能会出现超时和临时故障,如果失败消息在原始异常被引发后不久,则通常有可能成功处理失败的消息。

Apache Camel 重新发送支持在异常发生后对消息进行各种策略。配置重新发送的一些最重要的选项如下:

maximumRedeliveries ()
指定可以尝试重新发送的次数上限(默认为 0)。负值意味着始终尝试重新发送(等同于无限值)。
retryWhile()

指定一个 predicate ( Predicate 类型),它决定 Apache Camel 是否要继续重新设计。如果 predicate 在当前交换上评估为 true,则会尝试重新发送;否则,重新发送将停止,且不会进行进一步重新发送尝试。

这个选项优先于 maximumRedeliveries () 选项。

在 Java DSL 中,重新传送策略选项使用 onException 子句中的 DSL 命令来指定。例如,您可以指定最多 6 个 redeliveries,交换发送到 validationFailed deadletter 队列,如下所示:

onException(ValidationException.class)
  .maximumRedeliveries(6)
  .retryAttemptedLogLevel(org.apache.camel.LogginLevel.WARN)
  .to("activemq:validationFailed");

在 XML DSL 中,通过设置 redeliveryPolicy 元素的属性来指定重新发送策略选项。例如,前面的路由可以在 XML DSL 中表达,如下所示:

<onException useOriginalMessage="true">
    <exception>com.mycompany.ValidationException</exception>
    <redeliveryPolicy maximumRedeliveries="6"/>
    <to uri="activemq:validationFailed"/>
</onException>

在重新传送选项后,路由是 route swig-wagonis 的后一部分会被处理,直到最后一次重新传送尝试失败后才会处理。有关所有重新传送选项的详细描述,请参阅 第 6.3 节 “死信频道”

另外,您可以在 redeliveryPolicyProfile 实例中指定 redelivery 策略选项。然后,您可以使用 onException 元素的 redeliverPolicyRef 属性引用 redeliveryPolicyProfile 实例。例如,前面的路由可以表达如下:

<redeliveryPolicyProfile id="redelivPolicy" maximumRedeliveries="6" retryAttemptedLogLevel="WARN"/>

<onException useOriginalMessage="true" redeliveryPolicyRef="redelivPolicy">
    <exception>com.mycompany.ValidationException</exception>
    <to uri="activemq:validationFailed"/>
</onException>
注意

如果要在多个 onException 子句中重复使用相同的重新发送策略,使用 redeliveryPolicyProfile 的方法很有用。

条件 trapping

通过指定 onWhen 选项,可以通过指定 onWhen 选项进行带有 onException 的异常捕获。如果您在 onException 子句中指定 onWhen 选项,则只有在抛出异常与 子句匹配时,才会触发匹配项,而 onWhen predicate 会在当前交换上评估为 true

例如,在以下 Java DSL 片段中,第一个 onException 子句会触发,只有在抛出异常与 MyUserException 匹配 并且用户 标头在当前交换中不匹配时才触发:

// Java

// Here we define onException() to catch MyUserException when
// there is a header[user] on the exchange that is not null
onException(MyUserException.class)
    .onWhen(header("user").isNotNull())
    .maximumRedeliveries(2)
    .to(ERROR_USER_QUEUE);

// Here we define onException to catch MyUserException as a kind
// of fallback when the above did not match.
// Noitce: The order how we have defined these onException is
// important as Camel will resolve in the same order as they
// have been defined
onException(MyUserException.class)
    .maximumRedeliveries(2)
    .to(ERROR_QUEUE);

前面的 onException 子句可以在 XML DSL 中表达,如下所示:

<redeliveryPolicyProfile id="twoRedeliveries" maximumRedeliveries="2"/>

<onException redeliveryPolicyRef="twoRedeliveries">
    <exception>com.mycompany.MyUserException</exception>
    <onWhen>
        <simple>${header.user} != null</simple>
    </onWhen>
    <to uri="activemq:error_user_queue"/>
</onException>

<onException redeliveryPolicyRef="twoRedeliveries">
    <exception>com.mycompany.MyUserException</exception>
    <to uri="activemq:error_queue"/>
</onException>

处理异常

默认情况下,当路由中间出现异常时,当前交换的处理会中断,而抛出的异常会在路由开始时传播到消费者端点。触发 onException 子句时,其行为基本上相同,但 onException 子句在抛出异常被传播到前执行一些处理。

但是,这种默认行为 不是 处理异常的唯一方法。onException 提供各种选项来修改异常处理行为,如下所示:

  • 抑制异常重新 增长,您可以选择在 onException 子句完成后阻止再箭头异常。换句话说,在这种情况下,异常 不会在 路由开始时传播到消费者端点。
  • 继续处理 wagon- swig 您可以选择从最初发生异常时恢复对交换的正常处理。隐式来说,这种方法也会阻止增长异常。
  • 发送消息时,会发送一个 特殊情况,其中路由开始时的消费者端点需要回复(即 InOut MEP),您可能希望构建自定义故障回复消息,而不是将异常传播到消费者端点。

阻止异常增长

要防止当前异常被重新处理并传播到消费者端点,您可以在 Java DSL 中将 handled () 选项设置为 true,如下所示:

onException(ValidationException.class)
  .handled(true)
  .to("activemq:validationFailed");

在 Java DSL 中,handled () 选项的参数可以是布尔值类型、Predicate 类型或 Expression 类型(如果它评估为非null 值,则任何非布尔值表达式被解释为 true )。

可以使用 处理 的元素,将相同的路由配置为阻止 XML DSL 中的再增长异常,如下所示:

<onException>
    <exception>com.mycompany.ValidationException</exception>
    <handled>
        <constant>true</constant>
    </handled>
    <to uri="activemq:validationFailed"/>
</onException>

继续处理

要继续处理最初抛出异常的路由中的当前消息,您可以在 Java DSL 中将 continue 选项设置为 true,如下所示:

onException(ValidationException.class)
  .continued(true);

在 Java DSL 中,继续 () 选项的参数可以是布尔值类型、Predicate 类型或 Expression 类型(如果它评估为非null 值,则任何非布尔值表达式被解释为 true )。

可以使用 continued 元素在 XML DSL 中配置相同的路由,如下所示:

<onException>
    <exception>com.mycompany.ValidationException</exception>
    <continued>
        <constant>true</constant>
    </continued>
</onException>

发送响应

当启动路由的消费者端点需要回复时,您可能需要构建自定义故障回复消息,而不是只是让抛出异常传播到消费者。在这种情况下,需要遵循两个基本步骤:使用 handled 选项阻止再增长异常;并使用 handled 选项填充交换的 Out 消息插槽。

例如,以下 Java DSL 片段演示了如何在发生 MyFunctionalException 异常时发送包含文本字符串 Sorry 的回复消息:

// we catch MyFunctionalException and want to mark it as handled (= no failure returned to client)
// but we want to return a fixed text response, so we transform OUT body as Sorry.
onException(MyFunctionalException.class)
    .handled(true)
    .transform().constant("Sorry");

如果您要向客户端发送错误响应,您通常希望在响应中包含异常消息的文本。您可以使用 exceptionMessage () 构建器方法访问当前异常消息的文本。例如,您可以发送一个回复,其中包含发生 MyFunctionalException 异常时的异常消息的文本,如下所示:

// we catch MyFunctionalException and want to mark it as handled (= no failure returned to client)
// but we want to return a fixed text response, so we transform OUT body and return the exception message
onException(MyFunctionalException.class)
    .handled(true)
    .transform(exceptionMessage());

例外消息文本也可以通过 exception.message 变量从 Simple 语言访问。例如,您可以在回复消息中嵌入当前的异常文本,如下所示:

// we catch MyFunctionalException and want to mark it as handled (= no failure returned to client)
// but we want to return a fixed text response, so we transform OUT body and return a nice message
// using the simple language where we want insert the exception message
onException(MyFunctionalException.class)
    .handled(true)
    .transform().simple("Error reported: ${exception.message} - cannot process this message.");

前面的 onException 子句可以在 XML DSL 中表达,如下所示:

<onException>
    <exception>com.mycompany.MyFunctionalException</exception>
    <handled>
        <constant>true</constant>
    </handled>
    <transform>
        <simple>Error reported: ${exception.message} - cannot process this message.</simple>
    </transform>
</onException>

在处理异常时抛出异常

在处理现有异常时抛出的异常(换句话说,在处理一个 onException 子句的过程中会抛出一个异常)。此类例外由特殊的回退异常处理器处理,它处理异常,如下所示:

  • 所有现有异常处理程序将被忽略,处理会立即失败。
  • 记录新异常。
  • 在交换对象上设置新的例外。

简单的策略避免了复杂的故障场景,它们可能最终出现 onException 子句被锁定到无限循环中。

范围

onException 子句可以在以下任何一个范围内有效:

  • RouteBuilder 范围 wagon- onException 子句在 RouteBuilder.configure () 方法内定义为 standalone 语句,会影响 RouteBuilder 实例中定义的所有路由。另一方面,这些 onException 子句对任何其他 RouteBuilder 实例中定义的路由 没有影响。在路由定义之前,必须 出现 onException 子句。

    到此点的所有示例都使用 RouteBuilder 范围来定义。

  • 路由范围 wagon- onException 子句也可以直接嵌入路由中。这些 onException 子句 仅影响 在其中定义的路由。

路由范围

您可以在路由定义内任何位置嵌入一个 onException 子句,但您必须使用 end () DSL 命令终止嵌入的 onException 子句。

例如,您可以在 Java DSL 中定义嵌入的 onException 子句,如下所示:

// Java
from("direct:start")
  .onException(OrderFailedException.class)
    .maximumRedeliveries(1)
    .handled(true)
    .beanRef("orderService", "orderFailed")
    .to("mock:error")
  .end()
  .beanRef("orderService", "handleOrder")
  .to("mock:result");

您可以在 XML DSL 中定义内嵌的 Exception 子句,如下所示:

<route errorHandlerRef="deadLetter">
    <from uri="direct:start"/>
    <onException>
        <exception>com.mycompany.OrderFailedException</exception>
        <redeliveryPolicy maximumRedeliveries="1"/>
        <handled>
            <constant>true</constant>
        </handled>
        <bean ref="orderService" method="orderFailed"/>
        <to uri="mock:error"/>
    </onException>
    <bean ref="orderService" method="handleOrder"/>
    <to uri="mock:result"/>
</route>

2.3.2. 错误处理程序

概述

errorHandler () 子句提供与 onException 子句类似的功能,但这种机制 无法在 不同的异常类型之间差异。errorHandler () 子句是 Apache Camel 提供的原始异常处理机制,在实施 onException 子句之前可用。

Java DSL 示例

errorHandler () 子句在 RouteBuilder 类中定义,并应用到 RouteBuilder 类中的所有路由。每当其中一个适用的路由 中都发生异常 时,会触发它。例如,要定义一个错误处理程序,将所有失败的交换路由到 ActiveMQ deadLetter 队列,您可以定义一个 RouteBuilder,如下所示:

public class MyRouteBuilder extends RouteBuilder {

    public void configure() {
        errorHandler(deadLetterChannel("activemq:deadLetter"));

        // The preceding error handler applies
        // to all of the following routes:
        from("activemq:orderQueue")
          .to("pop3://fulfillment@acme.com");
        from("file:src/data?noop=true")
          .to("file:target/messages");
        // ...
    }
}

但是,在重新发送的所有尝试都已耗尽之前,不会发生重定向到死信频道。

XML DSL 示例

在 XML DSL 中,您可以使用 errorHandler 元素在 camelContext 范围内定义一个错误处理程序。例如,要定义一个错误处理程序,将所有失败的交换路由到 ActiveMQ deadLetter 队列,您可以定义 errorHandler 元素,如下所示:

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:camel="http://camel.apache.org/schema/spring"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
    http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">

    <camelContext xmlns="http://camel.apache.org/schema/spring">
        <errorHandler type="DeadLetterChannel"
                      deadLetterUri="activemq:deadLetter"/>
        <route>
            <from uri="activemq:orderQueue"/>
            <to uri="pop3://fulfillment@acme.com"/>
        </route>
        <route>
            <from uri="file:src/data?noop=true"/>
            <to uri="file:target/messages"/>
        </route>
    </camelContext>

</beans>

错误处理程序的类型

表 2.1 “错误处理程序类型” 提供对您可以定义的不同类型的错误处理程序的概述。

表 2.1. 错误处理程序类型
Java DSL BuilderXML DSL 类型属性描述

defaultErrorHandler()

DefaultErrorHandler

将异常传播到调用者并支持重新传送策略,但它不支持死信队列。

deadLetterChannel()

DeadLetterChannel

支持与默认错误处理程序相同的功能,并且还支持死信队列。

loggingErrorChannel()

LoggingErrorChannel

每当发生异常时,记录异常文本。

noErrorHandler()

NoErrorHandler

可以用来禁用错误处理程序的 dummy 处理程序实现。

 

TransactionErrorHandler

转换路由的错误处理程序。默认事务错误处理程序实例会自动用于标记为 transacted 的路由。

2.3.3. doTry, doCatch, and doFinally

概述

要在路由内处理异常,您可以使用 doTrydoCatchdoFinally 子句的组合,它们处理异常与 Java 的 尝试、捕获和 finally 块类似。

doCatch 和 Java catch 之间的相似性

通常,路由定义中的 doCatch () 子句的行为与 Java 代码中的 catch () 语句类似。特别是,doCatch () 子句支持以下功能:

  • 多个 doCatch  子句 swig-您可在单个 doTry 块中有多个 doCatch 子句。doCatch 子句按照其出现的顺序进行测试,就像 Java catch () 语句一样。Apache Camel 执行与抛出异常匹配的第一个 doCatch 子句。

    注意

    这个算法与 onException 子句的 exception 匹配算法不同,详情请参阅 第 2.3.1 节 “onException Clause”

  • 使用构造来重新增长异常 wagon- swig 您可以从 doCatch 子句中重新调整当前的异常(请参阅 “doCatch 中的重新增长异常”一节)。

doCatch 的特殊特性

但是,doCatch () 子句有一些特殊功能,但 Java catch () 语句中没有模拟。以下功能特定于 doCatch ()

Example

以下示例演示了如何在 Java DSL 中编写 doTry 块,其中执行 doCatch () 子句,如果出现 IOException 异常或 IllegalStateException 异常,并且 始终执行 doFinally () 子句,无论是否引发异常。

from("direct:start")
    .doTry()
        .process(new ProcessorFail())
        .to("mock:result")
    .doCatch(IOException.class, IllegalStateException.class)
        .to("mock:catch")
    .doFinally()
        .to("mock:finally")
    .end();

或者,在 Spring XML 中:

<route>
    <from uri="direct:start"/>
    <!-- here the try starts. its a try .. catch .. finally just as regular java code -->
    <doTry>
        <process ref="processorFail"/>
        <to uri="mock:result"/>
        <doCatch>
            <!-- catch multiple exceptions -->
            <exception>java.io.IOException</exception>
            <exception>java.lang.IllegalStateException</exception>
            <to uri="mock:catch"/>
        </doCatch>
        <doFinally>
            <to uri="mock:finally"/>
        </doFinally>
    </doTry>
</route>

doCatch 中的重新增长异常

使用 structs 可以在 doCatch () 子句中重新增加异常,如下所示:

from("direct:start")
    .doTry()
        .process(new ProcessorFail())
        .to("mock:result")
    .doCatch(IOException.class)
         .to("mock:io")
        // Rethrow the exception using a construct instead of handled(false) which is deprecated in a doTry/doCatch clause.
        .throwException(new IllegalArgumentException("Forced"))
    .doCatch(Exception.class)
        // Catch all other exceptions.
        .to("mock:error")
    .end();
注意

您还可以使用处理器而不是 handled (false) (在 doTry/doCatch 子句中弃用的处理器)重新增长异常:

.process(exchange -> {throw exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class);})

在前面的示例中,如果 doCatch () 出现 IOException,当前的交换将发送到 mock:io 端点,则 IOException 为 rerown。这会在路由开始时(在 from () 命令中)提供消费者端点,可以有机会处理异常。

以下示例演示了如何在 Spring XML 中定义相同的路由:

<route>
    <from uri="direct:start"/>
    <doTry>
        <process ref="processorFail"/>
        <to uri="mock:result"/>
        <doCatch>
            <to uri="mock:io"/>
            <throwException message="Forced" exceptionType="java.lang.IllegalArgumentException"/>
        </doCatch>
        <doCatch>
            <!-- Catch all other exceptions. -->
            <exception>java.lang.Exception</exception>
            <to uri="mock:error"/>
        </doCatch>
    </doTry>
</route>

条件异常使用 onWhen

Apache Camel doCatch () 子句的一个特殊功能是您可以根据运行时评估的表达式条件化异常的捕获。换句话说,如果您使用表单的 子句来捕获异常,则 doCatch (ExceptionList).doWhen ( Expression ) 只会发现异常,如果 predicate 表达式、表达式,在运行时评估为 true

例如,以下 doTry 块将捕获异常( IOExceptionIllegalStateException ),只有在异常消息包含单词 Severe 时:

from("direct:start")
    .doTry()
        .process(new ProcessorFail())
        .to("mock:result")
    .doCatch(IOException.class, IllegalStateException.class)
        .onWhen(exceptionMessage().contains("Severe"))
        .to("mock:catch")
    .doCatch(CamelExchangeException.class)
        .to("mock:catchCamel")
    .doFinally()
        .to("mock:finally")
    .end();

或者,在 Spring XML 中:

<route>
    <from uri="direct:start"/>
    <doTry>
        <process ref="processorFail"/>
        <to uri="mock:result"/>
        <doCatch>
            <exception>java.io.IOException</exception>
            <exception>java.lang.IllegalStateException</exception>
            <onWhen>
                <simple>${exception.message} contains 'Severe'</simple>
            </onWhen>
            <to uri="mock:catch"/>
        </doCatch>
        <doCatch>
            <exception>org.apache.camel.CamelExchangeException</exception>
            <to uri="mock:catchCamel"/>
        </doCatch>
        <doFinally>
            <to uri="mock:finally"/>
        </doFinally>
    </doTry>
</route>

doTry 中的嵌套条件

有多种选项可用于将 Camel 异常处理添加到 JavaDSL 路由中。dotry () 创建用于处理异常的尝试或捕获块,对路由特定错误处理很有用。

如果要捕获 ChoiceDefinition 内异常,您可以使用以下 doTry 块:

from("direct:wayne-get-token").setExchangePattern(ExchangePattern.InOut)
           .doTry()
              .to("https4://wayne-token-service")
              .choice()
                  .when().simple("${header.CamelHttpResponseCode} == '200'")
                     .convertBodyTo(String.class)
.setHeader("wayne-token").groovy("body.replaceAll('\"','')")
                     .log(">> Wayne Token : ${header.wayne-token}")
                .endChoice()

.doCatch(java.lang.Class (java.lang.Exception>)
              .log(">> Exception")
           .endDoTry();

from("direct:wayne-get-token").setExchangePattern(ExchangePattern.InOut)
           .doTry()
              .to("https4://wayne-token-service")
           .doCatch(Exception.class)
              .log(">> Exception")
           .endDoTry();

2.3.4. 传播 SOAP Exceptions

概述

Camel CXF 组件提供与 Apache CXF 的集成,使您能够从 Apache Camel 端点发送和接收 SOAP 消息。您可以在 XML 中轻松定义 Apache Camel 端点,然后使用端点的 bean ID 在路由中引用该端点。如需了解更多详细信息,请参阅 Apache Camel 组件参考指南 中的 CXF

如何传播堆栈追踪信息

可以配置 CXF 端点,以便在服务器端引发 Java 异常时,异常的堆栈追踪会被放入故障消息并返回到客户端。要启用这种情况,请将 dataFormat 设置为 PAYLOAD,并在 cxfEndpoint 元素中将 faultStackTraceEnabled 属性设置为 true,如下所示:

<cxf:cxfEndpoint id="router" address="http://localhost:9002/TestMessage"
    wsdlURL="ship.wsdl"
    endpointName="s:TestSoapEndpoint"
    serviceName="s:TestService"
    xmlns:s="http://test">
  <cxf:properties>
    <!-- enable sending the stack trace back to client; the default value is false-->
    <entry key="faultStackTraceEnabled" value="true" />
    <entry key="dataFormat" value="PAYLOAD" />
  </cxf:properties>
</cxf:cxfEndpoint>

为安全起见,堆栈跟踪不包括导致异常(即,由 导致的堆栈追踪的一部分)。如果要在堆栈追踪中包含导致异常,在 cxfEndpoint 元素中将 exceptionMessageCauseEnabled 属性设置为 true,如下所示:

<cxf:cxfEndpoint id="router" address="http://localhost:9002/TestMessage"
    wsdlURL="ship.wsdl"
    endpointName="s:TestSoapEndpoint"
    serviceName="s:TestService"
    xmlns:s="http://test">
  <cxf:properties>
    <!-- enable to show the cause exception message and the default value is false -->
    <entry key="exceptionMessageCauseEnabled" value="true" />
    <!-- enable to send the stack trace back to client,  the default value is false-->
    <entry key="faultStackTraceEnabled" value="true" />
    <entry key="dataFormat" value="PAYLOAD" />
  </cxf:properties>
</cxf:cxfEndpoint>
警告

您应该只启用 exceptionMessageCauseEnabled 标志用于测试和诊断。对于服务器而言,正常做法是让恶意用户探测到服务器的最初原因。

Red Hat logoGithubRedditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

通过我们的产品和服务,以及可以信赖的内容,帮助红帽用户创新并实现他们的目标。

让开源更具包容性

红帽致力于替换我们的代码、文档和 Web 属性中存在问题的语言。欲了解更多详情,请参阅红帽博客.

關於紅帽

我们提供强化的解决方案,使企业能够更轻松地跨平台和环境(从核心数据中心到网络边缘)工作。

© 2024 Red Hat, Inc.