2.3. 异常处理


摘要

Apache Camel 提供了几种不同的机制,它可让您以不同的粒度级别处理异常:您可以使用 doTrydoCatch 来处理路由内的异常,并最终 执行;或者,您可以指定每个异常类型执行哪些操作,并将这些规则应用于使用 Exception 的 RouteBuilder 中所有路由中的所有路由 ; 或者,您可以指定 所有 异常类型执行的操作,并使用 错误处理程序 将这一规则应用于 RouteBuilder 中的所有路由。

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

2.3.1. onException Clause

概述

onException 子句是捕获异常的一种强大的机制,可在一个或多个路由中发生:它特定于类型,使您能够定义不同的操作来处理不同的异常类型;它允许您定义使用相同(实际上,稍有的扩展)语法的操作,作为路由,从而在您处理异常情况下,以方便您处理异常的方式;它基于一个捕获模型,这基于一个结果。

使用 onException 的 Trapping 异常

onException 子句是捕获异常的机制。也就是说,一旦定义了 onException 子句,它将陷阱在路由中的任何点上发生异常。这与捕获异常的 Java 试用/分散机制不同,只有在将特定的代码片段 明确 包含在 try 块中时。

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

Java DSL 示例

在以下 Java DSL 示例中,onException 子句应用到 RouteBuilder 类中定义的所有路由。如果在处理其中任一路由(来自"seda:inputA")来自("seda:inputB")时出现 ValidationException 异常,则 onException 子句将当前的交换重定向到 verify Failed 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>

Trapping 多个例外

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

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>

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

  1. 如果引发异常是 链的异常 (即,捕获异常并作为不同的异常),则最常见的异常类型最初是匹配的基础。这个例外测试如下:

    1. 如果 exception-to-test 正好在 onException 子句中指定的类型(使用 instanceof测试),则会触发匹配项。
    2. 如果 exception-to-test 是 onException 子句中指定的类型的子类型,则会触发匹配项。
  2. 如果最嵌套的异常无法获得匹配项,则将测试链(嵌套异常)中的下一个异常。测试会继续链,直到触发匹配或链用尽。
注意

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

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

字母频道

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

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

使用原始消息

当路由期间出现异常时,交换中的消息可能已被大量修改(甚至不能被人读取)。通常,管理员更容易决定要执行哪些正确性操作,如果死信队列中可见的消息是 原始消息,如路由开始时收到的消息。useOriginalMessage 选项默认为 false,但如果在错误处理程序上配置,则会自动启用。

注意

使用OriginalMessage 选项可导致应用到 Camel 路由时出现意外行为,该路由将消息发送到多个端点,或将消息拆分为部分。原始消息可能无法在多广播、斯plitter 或 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 会在路由开始时复制原始消息,以确保在 使用OriginalMessage () 时原始消息可用。但是,如果在 Camel 上下文上将 setAllowUseOriginalMessage () 选项设为 false (这是默认设置 ),则原始消息将无法访问,您无法调用 useOriginalMessage ()

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

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

重新传送策略

Apache Camel 为您提供尝试 除发生异常的情况,而不是中断消息处理,并在出现异常时立即放弃信息。在网络系统中,超时发生且临时故障发生时,通常可能会成功处理失败的消息,如果在引发原始异常后马上进行恢复。

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

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

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

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

在 Java DSL 中,重新传送策略选项使用 onException 子句中的 DSL 命令来指定。例如,您可以指定最多 6 个回收,之后该交换会发送到 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>

重新传送选项的后,redelivery 选项的后后,才会被处理,直到最后一次重新传送尝试失败后才会被处理。有关所有重新传送选项的详情,请参考 第 6.3 节 “死信频道”

另外,您可以在 redeliveryPolicyProfile 实例中指定重新传送策略选项。然后,您可以使用 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 选项,可以对Exception 进行异常捕获。如果您在 onException 子句中指定 onWhen 选项,则仅在引发异常与 子句匹配时触发匹配,而 onWhen predicate 在当前交换上评估为 true

例如,在以下 Java DSL 片段中,第一个 onException 子句触发器(仅当引发异常与 MyUserException 匹配并且当前交换 中的用户 标头为非null)时:

// 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 提供了各种选项来修改异常处理行为,如下所示:

  • 抑制异常 rethrow cnf-you 选项,您可以选择在 Exception 子句后禁止重新增长异常。换句话说,在这种情况下,异常 不会 传播到路由开始时的使用者端点。
  • 继续处理 WWN-you 选项可以从最初发生异常时恢复正常处理交换。隐式,这种方法也会阻止重新浏览异常。
  • 如果路由开始时的消费者端点需要回复(即使用 InOut MEP),您可能更倾向于构建自定义故障回复消息,而不是传播异常到消费者端点。???

抑制异常重新箭头

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

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

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

同一路由可以配置为禁止使用 处理 元素的 XML DSL 中的 rerown 异常,如下所示:

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

继续处理

要从最初引发异常的路由中处理当前消息,您可以在 Java DSL 中将 continued 选项设为 true,如下所示:

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

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

同一路由可以在 XML DSL 中配置,使用 继续 元素,如下所示:

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

发送响应

当启动路由的消费者端点需要回复时,您可能更愿意构建自定义故障回复消息,而不是简单地将引发异常传播回消费者。在这种情况下,您需要执行两个基本步骤: 禁止 rethrown exception 使用 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 () builder 方法访问当前异常消息的文本。例如,您可以在发生 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 子句的过程中会引发异常)会以特殊方式处理。这种异常由特殊回退异常处理程序处理,它处理异常,如下所示:

  • 所有现有的异常处理程序将被忽略,并立即处理失败。
  • 已记录新的异常。
  • 在 Exchange 对象上设置了新的异常。

简单策略避免了复杂的故障情景,否则可能会出现 对Exception 子句被锁定在无限循环中。

范围

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

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

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

  • 路由范围 TOKEN- 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 中定义嵌入式 onException 子句,如下所示:

<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 () 子句提供与 Exception 子句类似的功能,但这种机制在不同的异常类型之间 无法识别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

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

2.3.3. doTry、doCatch 和 lastly

概述

要在路由内部处理异常,您可以使用 doTrydoCatchdoFinally 子句的组合,该子句以类似于 Java 的 尝试捕获最终 块的方式处理异常。

doCatch 和 Java 捕获之间的相似性

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

  • 在单一 do Try 块中可以有多个 doCatch 子句,其中有多个 doCatch 子句。doCatch 子句按照它们显示的顺序进行测试,就像 Java catch () 语句一样。Apache Camel 执行与引发异常匹配的第一个 doCatch 子句。

    注意

    这个算法与 Exception 子句计算机上计算机上使用 的异常匹配算法不同,请参阅 第 2.3.1 节 “onException Clause” 了解详细信息。

  • 使用 结构(请参阅 “在 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 中,或等效于 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 中增加异常

可以使用构造在 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();
注意

您还可以使用在 doTry/doCatch 子句中弃用的处理器 (false) 来重新增加异常:

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

在前面的示例中,如果 doCatch () 捕获了 IOException,则当前交换将发送到 mock:io 端点,然后 IOException 正在重新浏览。这为消费者端点在路由开始时(在 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

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 中,或等效于 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 Exception

概述

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.