2.3. 예외 처리

초록

Apache Camel은 다양한 수준의 세분성에서 예외를 처리할 수 있는 여러 가지 메커니즘을 제공합니다. doTry를 사용하여 경로 내에서 예외를 처리할 수 있습니다. doTry,doCatch, doFinally; 또는 각 예외 유형에 대해 수행할 작업을 지정하고 이 규칙을 Exception 을 사용하여 RouteBuilder 의 모든 경로에 적용할 수 있습니다. 또는 모든 예외 유형에 대해 수행할 작업을 지정하고 errorHandler 를 사용하여 RouteBuilder 의 모든 경로에 이 규칙을 적용할 수 있습니다.

예외 처리에 대한 자세한 내용은 6.3절. “dead Letter Channel” 을 참조하십시오.

2.3.1. onException

2.3.1.1. 개요

onException 절은 하나 이상의 경로에서 발생하는 예외를 트래핑하기 위한 강력한 메커니즘입니다. 즉, 유형별로 다른 예외 유형을 처리할 수 있는 고유한 작업을 정의할 수 있습니다. 따라서 기본적으로 동일한(실제로 확장) 구문을 사용하여 작업을 정의할 수 있으므로 예외를 처리하는 방식에 상당한 유연성을 제공하고 예외를 처리하는 방식에 상당한 유연성을 제공하고, 예외를 처리할 수 있습니다.

2.3.1.2. onException을 사용하여 예외를 트래핑

onException 절은 예외를 catch하는 대신 트래핑 을 위한 메커니즘입니다. 즉, onException 절을 정의하면 경로의 모든 지점에서 발생하는 예외를 트랩합니다. 이는 특정 코드 조각이 try 블록으로 명시적으로 묶은 경우에만 예외가 발생하는 Java try/catch 메커니즘과 대조됩니다.

onException 절을 정의할 때 실제로 발생하는 것은 Apache Camel 런타임이 try 블록의 각 경로 노드를 암시적으로 묶는 것입니다. 따라서 onException 절은 경로의 어느 시점에서 예외를 트래킹할 수 있습니다. 그러나 이 래핑은 자동으로 수행됩니다. 경로 정의에는 표시되지 않습니다.

2.3.1.3. Java DSL 예

다음 Java DSL 예제에서 onException 절은 RouteBuilder 클래스에 정의된 모든 경로에 적용됩니다. If a ValidationException exception occurs while processing either of the routes (from("seda:inputA") or from("seda:inputB"), the onException clause traps the exception and redirects the current exchange to the validationFailed JMS queue (which serves as a deadletter queue).

// 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");
  }
}

2.3.1.4. XML DSL 예

위 예제는 다음과 같이 onException 요소를 사용하여 예외 절을 정의하는 XML DSL로 표시할 수도 있습니다.

<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>

2.3.1.5. 여러 예외를 트랩

RouteBuilder 범위에서 예외를 해결하기 위해 여러 onException 절을 정의할 수 있습니다. 이를 통해 다양한 예외에 대한 응답으로 다양한 작업을 수행할 수 있습니다. 예를 들어 Java DSL에 정의된 다음과 같은 onException 절에서는 ValidationException,IOExceptionException 에 대해 서로 다른 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은 처음에 첫 번째 절에 대해 throw된 예외와 일치하려고 시도합니다. 첫 번째 절이 일치되지 않으면 다음 onException 절이 시도된 후 일치 항목이 발견될 때까지 계속 실행됩니다. 일치하는 각 시도는 다음 알고리즘에 의해 관리됩니다.

  1. throw된 예외가 체인된 예외 (즉, 예외가 catch되고 다른 예외로 다시 탐색된 경우)인 경우 가장 중첩된 예외 유형은 처음에 일치의 기반으로 사용됩니다. 이 예외는 다음과 같이 테스트됩니다.

    1. 예외-투-테스트에 정확히 onException 절에 지정된 형식이 있는 경우( 인스턴스를사용하여 테스트됨) 일치가 트리거됩니다.
    2. 예외-투-테스트가 onException 절에 지정된 형식의 하위 유형인 경우 일치가 트리거됩니다.
  2. 가장 중첩된 예외가 일치를 산출하지 못하면 체인의 다음 예외(래핑 예외)가 대신 테스트됩니다. 테스트는 일치가 트리거되거나 체인이 소진될 때까지 체인을 계속합니다.
참고

throwException EIP를 사용하면 간단한 언어 표현식에서 새 예외 인스턴스를 만들 수 있습니다. 예를 들어 현재 교환에서 사용 가능한 정보를 기반으로 동적으로 만들 수 있습니다.

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

2.3.1.6. Deadletter 채널

onException 사용의 기본 예제는 지금까지 모두 deadletter 채널 패턴을 악용했습니다. 즉, onException 절이 예외를 트래핑할 때 현재 교환은 특수 대상(종종 채널)으로 라우팅됩니다. deadletter 채널은 처리되지 않은 실패한 메시지의 보관 영역 역할을 합니다. 관리자는 나중에 메시지를 검사하고 어떤 작업을 수행해야 하는지 결정할 수 있습니다.

deadletter 채널 패턴에 대한 자세한 내용은 6.3절. “dead Letter Channel” 을 참조하십시오.

2.3.1.7. 원본 메시지 사용

경로 중간에서 예외가 발생하는 시점에, 교환의 메시지는 상당히 수정될 수 있었습니다(하나의 사람이 읽을 수도 있음). 경로 시작 시 수신되는 대로 문자 큐에 표시되는 메시지가 원본 메시지인 경우 관리자가 수행할 수정 작업을 보다 쉽게 결정할 수 있습니다. useOriginalMessage 옵션은 기본적으로 false 이지만 오류 처리기에 구성된 경우 자동으로 활성화됩니다.

참고

useOriginalMessage 옵션을 사용하면 여러 끝점에 메시지를 보내거나 메시지를 부분으로 분할하는 Camel 경로에 적용할 때 예기치 않은 동작이 발생할 수 있습니다. 중간 처리 단계가 원래 메시지를 수정하는 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입니다.

2.3.1.8. Redelivery policy

메시지 처리를 중단하고 예외가 발생하는 즉시 포기하는 대신 Apache Camel은 예외가 발생한 시점에서 메시지를 다시 전달할 수 있는 옵션을 제공합니다. 시간 초과가 발생하고 일시적인 오류가 발생하는 네트워크 시스템에서는 원래 예외가 발생한 직후에 실패한 메시지가 성공적으로 처리될 수 있는 경우가 많습니다.

Apache Camel 재전송은 예외가 발생한 후 메시지를 재전송하기 위한 다양한 전략을 지원합니다. 재전송을 구성하는 가장 중요한 옵션 중 일부는 다음과 같습니다.

maximumRedeliveries()
재전송할 수 있는 최대 횟수를 지정합니다(기본값은 0). 음수 값은 재전송이 항상 시도됨을 의미합니다(무제한 값과 동일).
retryWhile()

Apache Camel의 계속 재전송 여부를 결정하는 서술자(예: Predicate 유형)를 지정합니다. 서술자가 현재 교환에서 true 로 평가되면 재전송이 시도됩니다. 그렇지 않으면 재전송이 중지되고 추가 재전송 시도가 수행되지 않습니다.

이 옵션은 maximumRedeliveries() 옵션보다 우선합니다.

Java DSL에서 redelivery 정책 옵션은 onException 절의 DSL 명령을 사용하여 지정됩니다. 예를 들어 다음과 같이 교환이 validationFailed deadletter 큐로 전송되는 최대 6개의 재전송을 지정할 수 있습니다.

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>

재전송 옵션은 마지막 재전송 시도가 실패 할 때까지 재전송 옵션이 설정되지 않은 후 경로의 후의 후. 모든 재전송 옵션에 대한 자세한 설명은 6.3절. “dead Letter Channel” 을 참조하십시오.

또는 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>
참고

redeliveryPolicyProfile 을 사용하는 방법은 여러 onException 절에서 동일한 재전송 정책을 다시 사용하려는 경우 유용합니다.

2.3.1.9. 조건부 트래핑

onException 을 사용한 예외 트래핑은 on When 옵션을 지정하여 조건부로 수행할 수 있습니다. onException 절에서 onIf 옵션을 지정하면 throw된 예외가 해당 절 일치하고 현재 교환 에서 true 로 평가되는 경우에만 일치가 트리거됩니다.

예를 들어 다음 Java DSL 조각에서 throw된 예외가 MyUserException 과 일치하고 현재 교환에서 사용자 헤더가 null이 아닌 경우에만 첫 번째 onException 절이 트리거됩니다.

// 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>

2.3.1.10. 예외 처리

기본적으로 경로 중간에서 예외가 발생하는 경우 현재 교환 처리가 중단되고 경로 시작 시 throw된 예외가 소비자 끝점으로 다시 전파됩니다. onException 절이 트리거되면 throw된 예외가 다시 전파되기 전에 onException 절이 일부 처리를 수행하는 경우를 제외하고 기본적으로 동작이 동일합니다.

그러나 이 기본 동작은 예외를 처리하는 유일한 방법은 아닙니다. onException 은 다음과 같이 예외 처리 동작을 수정하는 다양한 옵션을 제공합니다.

  • onException 절이 완료된 후 취소 예외를 억제하는 옵션이 있습니다. ??? 즉, 이 경우 예외는 경로 시작 시 소비자 끝점으로 다시 전파 되지 않습니다.
  • 계속 처리 의 경우 예외가 원래 발생한 시점에서 교환의 정상적인 처리를 다시 시작할 수 있습니다. 암시적으로 이 방법은 rethrown 예외도 표시하지 않습니다.
  • 경로 시작 시 소비자 끝점이 응답을 예상하는 특수한 경우(즉, InOut MEP가 있음) 예외를 소비자 엔드포인트로 다시 전파하는 대신 사용자 지정 오류 응답 메시지를 생성하는 것을 선호할 수 있습니다.

2.3.1.11. 예외 취소 비활성화

현재 예외가 다시 생성되고 소비자 끝점으로 다시 전파되지 않도록 하려면 다음과 같이 Java DSL에서 handled() 옵션을 true 로 설정할 수 있습니다.

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

Java DSL에서 handled() 옵션에 대한 인수는 부울 유형, Predicate 유형 또는 Expression 유형 중 하나일 수 있습니다(boolean 이외의 표현식이 null 이외의 값으로 평가되면).

다음과 같이 처리된 요소를 사용하여 XML DSL에서 rethrown 예외를 억제하도록 동일한 경로를 구성할 수 있습니다.

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

2.3.1.12. 계속 처리

예외가 원래 throw된 경로 지점에서 현재 메시지를 계속 처리하려면 다음과 같이 Java DSL에서 지속적인 옵션을 true 로 설정할 수 있습니다.

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

Java DSL에서 continued() 옵션에 대한 인수는 부울 유형, Predicate 유형 또는 Expression 유형일 수 있습니다(모든 비boolean 표현식이 true 로 해석되는 경우 null이 아닌 값으로 평가되는 경우).

계속되는 요소를 사용하여 다음과 같이 XML DSL에서 동일한 경로를 구성할 수 있습니다.

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

2.3.1.13. 응답 전송

경로를 시작하는 소비자 끝점에 회신이 필요한 경우 throw된 예외가 소비자에게 다시 전파되도록 하는 대신 사용자 정의 오류 응답 메시지를 구성하는 것을 선호할 수 있습니다. 이 경우 수행해야 하는 두 가지 필수 단계가 있습니다. 즉, 처리된 옵션을 사용하여 복구 예외를 표시하지 않고 교환의 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>

2.3.1.14. 예외를 처리하는 동안 throw되는 예외

기존 예외를 처리하는 동안 throw되는 예외(즉, onException 절 처리 중에서 throw되는 예외)는 특별한 방식으로 처리됩니다.An exception that gets thrown while handling an existing exception (in other words, one that gets thrown in the middle of processing an onException clause) is handled in a special way. 이러한 예외는 다음과 같이 예외를 처리하는 특수 대체 예외 처리기에 의해 처리됩니다.

  • 기존 예외 처리기는 모두 무시되고 처리가 즉시 실패합니다.
  • 새 예외가 기록됩니다.
  • 새로운 예외는 교환 오브젝트에 설정됩니다.

간단한 전략은 onException 절이 무한 루프에 고정되는 상태로 끝날 수 있는 복잡한 실패 시나리오를 방지합니다.

2.3.1.15. 범위

onException 절은 다음 범위 중 하나에서 효과적일 수 있습니다.

  • RouteBuilder 범위 cidr- onException 절은 RouteBuilder.configure() 메서드 내의 독립 실행형 문으로 정의된 모든 RouteBuilder 인스턴스에 정의된 모든 경로에 영향을 미칩니다. 반면, 이러한 onException 절은 다른 RouteBuilder 인스턴스 내에 정의된 경로에 영향을 미치지 않습니다. onException 절은 경로 정의 앞에 표시되어야 합니다.

    이 시점까지의 모든 예제는 RouteBuilder 범위를 사용하여 정의됩니다.

  • 경로 범위 Cryostat- onException 절을 경로 내에 직접 포함할 수도 있습니다. 이러한 onException 절은 정의된 경로에 영향을 미칩니다.

2.3.1.16. 경로 범위

경로 정의 내부에 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. 오류 처리기

2.3.2.1. 개요

errorHandler() 절은 onException 절과 유사한 기능을 제공합니다. 단, 이 메커니즘은 다른 예외 유형을 구별할 수 없습니다. errorHandler() 절은 Apache Camel에서 제공하는 원래 예외 처리 메커니즘이며 onException 절이 구현되기 전에 사용할 수 있었습니다.

2.3.2.2. 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");
        // ...
    }
}

그러나 dead letter channel으로의 리디렉션은 다시 전송 시 모든 시도가 소진될 때까지 발생하지 않습니다.

2.3.2.3. 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.3.2.4. 오류 처리기 유형

표 2.1. “오류 처리기 유형” 정의할 수 있는 다양한 유형의 오류 처리기에 대한 개요를 제공합니다.

표 2.1. 오류 처리기 유형

Java DSL BuilderXML DSL 유형 속성설명

defaultErrorHandler()

DefaultErrorHandler

예외를 호출자로 다시 전파하고 재전송 정책을 지원하지만 dead letter 큐는 지원하지 않습니다.

deadLetterChannel()

DeadLetterChannel

기본 오류 처리기와 동일한 기능을 지원하며, 또한 dead letter 큐를 지원합니다.

loggingErrorChannel()

LoggingErrorChannel

예외가 발생할 때마다 예외 텍스트를 기록합니다.

noErrorHandler()

NoErrorHandler

오류 처리기를 비활성화하는 데 사용할 수 있는 더미 처리기 구현입니다.

 

TransactionErrorHandler

트랜잭션된 경로에 대한 오류 처리기입니다. 트랜잭션으로 표시된 경로에 기본 트랜잭션 오류 처리기 인스턴스가 자동으로 사용됩니다.

2.3.3. DoTry, doCatch 및 doFinally

2.3.3.1. 개요

경로 내에서 예외를 처리하기 위해 doTry,doCatchdoFinally 절을 조합하여 Java의 시도,catch, finally 블록과 유사한 방식으로 예외를 처리할 수 있습니다.

2.3.3.2. doCatch와 Java catch 간의 유사점

일반적으로 경로 정의의 doCatch() 절은 Java 코드에서 catch() 문과 유사한 방식으로 작동합니다. 특히 doCatch() 절에서 다음 기능을 지원합니다.

  • 하나의 do Try 블록 내에 여러 doCatch 절을 사용할 수 있습니다. doCatch 절은 Java catch() 문과 마찬가지로 표시되는 순서대로 테스트됩니다. Apache Camel은 throw된 예외와 일치하는 첫 번째 doCatch 절을 실행합니다.

    참고

    이 알고리즘은 onException 절에서 사용하는 예외 일치 알고리즘과 다릅니다. 자세한 내용은 2.3.1절. “onException” 을 참조하십시오.

  • 처리된 하위 복제를 사용하여 doCatch 절 내에서 현재 예외를 다시 시작할 수 있습니다( “doCatch에서 예외 제거”참조).

2.3.3.3. doCatch의 특수 기능

그러나 Java catch() 문에 유사한 기능이 없는 doCatch() 절의 몇 가지 특수 기능이 있습니다. 다음 기능은 doCatch() 에만 적용됩니다.

2.3.3.4. 예제

다음 예제에서는 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>

2.3.3.5. doCatch에서 예외 제거

다음과 같이 handled() 하위 복제를 호출하고 해당 인수가 false 로 설정된 경우 doCatch() 절에서 예외를 다시 시작할 수 있습니다.

from("direct:start")
    .doTry()
        .process(new ProcessorFail())
        .to("mock:result")
    .doCatch(IOException.class)
        // mark this as NOT handled, eg the caller will also get the exception
        .handled(false)
        .to("mock:io")
    .doCatch(Exception.class)
        // and catch all other exceptions
        .to("mock:error")
    .end();

이전 예에서 IOExceptiondoCatch() 에 의해 catch되면 현재 교환이 mock:io 엔드포인트로 전송되고 IOException 이 다시 검색됩니다. 이렇게 하면 경로 시작 시 소비자 끝점( from() 명령)도 예외를 처리할 수 있습니다.

다음 예제에서는 Spring XML에서 동일한 경로를 정의하는 방법을 보여줍니다.

<route>
    <from uri="direct:start"/>
    <doTry>
        <process ref="processorFail"/>
        <to uri="mock:result"/>
        <doCatch>
            <exception>java.io.IOException</exception>
            <!-- mark this as NOT handled, eg the caller will also get the exception -->
            <handled>
                <constant>false</constant>
            </handled>
            <to uri="mock:io"/>
        </doCatch>
        <doCatch>
            <!-- and catch all other exceptions they are handled by default (ie handled = true) -->
            <exception>java.lang.Exception</exception>
            <to uri="mock:error"/>
        </doCatch>
    </doTry>
</route>

2.3.3.6. on When 사용 중 조건부 예외 catching

Apache Camel doCatch() 절의 특수 기능은 런타임에 평가되는 표현식을 기반으로 예외 catch를 조건부화할 수 있다는 것입니다. 즉, 양식의 절을 사용하여 예외를 catch하는 경우 doCatch(ExceptionList).do When(Expression) 에서는 조건자 표현식, Expression, 런타임 시 true 로 평가되는 경우에만 예외가 catch됩니다.

예를 들어 다음 doTry 블록은 예외인 IOExceptionIllegalStateException 이 예외를 catch합니다. 예외 메시지에 단어 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>

2.3.3.7. doTry의 중첩된 조건

JavaDSL 경로에 Camel 예외 처리를 추가하는 데 사용할 수 있는 다양한 옵션이 있습니다. dotry() 는 예외를 처리하기 위한 try 또는 catch 블록을 생성하고 경로별 오류 처리에 유용합니다.

ChoiceDefinition 내에서 예외를 catch하려면 다음 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. Cryostat 예외 전파

2.3.4.1. 개요

Camel CXF 구성 요소는 Apache CXF와 통합되므로 Apache Camel 끝점에서 Cryostat 메시지를 보내고 받을 수 있습니다. XML로 Apache Camel 엔드포인트를 쉽게 정의할 수 있으며 엔드포인트의 8080 ID를 사용하여 경로에서 참조할 수 있습니다. 자세한 내용은 Apache Camel 구성 요소 참조 가이드의 CXF 를 참조하십시오.

2.3.4.2. 스택 추적 정보를 전파하는 방법

Java 예외가 서버 측에서 throw될 때 예외에 대한 스택 추적이 오류 메시지로 마샬링되어 클라이언트에 반환되도록 CXF 엔드포인트를 구성할 수 있습니다. 이 페어링을 사용하려면 dataFormatPAYLOAD 로 설정하고 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 플래그만 활성화해야 합니다. 서버는 적대적인 사용자가 서버를 프로브하는 것을 더 어렵게 만들기 위해 예외의 원래 원인을 숨기는 것이 일반적인 방법입니다.