简体   繁体   English

使用拦截器时的骆驼异常处理行为

[英]Camel exception handling behaviour when using interceptor

In a unit test I want to simulate that an Exception occurs. 在单元测试中,我要模拟发生Exception情况。

I expect to receive one message at the "mock:count" endpoint, because of the doTry/doCatch -block. 由于doTry/doCatch ,我希望在“ mock:count”端点上收到一条消息。 Why is this not happening and why is the Exception handled by the general onException -block? 为什么没有发生这种情况,为什么一般的onException -block处理Exception

import org.apache.camel.LoggingLevel;
import org.apache.camel.builder.AdviceWithRouteBuilder;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.mock.MockEndpoint;
import org.apache.camel.test.junit4.CamelTestSupport;
import org.apache.cxf.binding.soap.SoapFault;
import org.junit.Test;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Text;

public class TestClass extends CamelTestSupport {
   @Override
   protected RouteBuilder createRouteBuilder() throws Exception {
      return new RouteBuilder() {
         @Override
         public void configure() throws Exception {
            onException(Exception.class)
                  .log(LoggingLevel.INFO, "outer catch")
                  .handled(true);

            from("direct:start")
                  .doTry()
                     .to("mock:exception")

                  .doCatch(Exception.class)
                     .log(LoggingLevel.INFO, "inner catch")
                     .to("mock:count")
                  .end();
         }
      };
   }

   @Test
   public void testBlaat() throws Exception {
      final SoapFault soapFault = new SoapFault("Something clearly went wrong", SoapFault.FAULT_CODE_CLIENT);
      Element detail = soapFault.getOrCreateDetail();
      Document doc = detail.getOwnerDocument();
      Text tn = doc.createTextNode("Fault details");
      detail.appendChild(tn);

      context.getRouteDefinitions().get(0).adviceWith(context, new AdviceWithRouteBuilder() {
         @Override
         public void configure() throws Exception {
            interceptSendToEndpoint("mock:exception").throwException(new Exception("test"));
         }
      });

      template.sendBody("direct:start", "start");

      MockEndpoint endpoint = getMockEndpoint("mock:count");
      endpoint.expectedMessageCount(1);

      assertMockEndpointsSatisfied();

   }
}

It turns out that exceptions thrown from an AdviceWithRouteBuilder are not seen by the RouteDefinition 's doTry/doCatch when the route is intercepted by the AdviceWithRouteBuilder because they are on different channels. 事实证明,从抛出的异常AdviceWithRouteBuilder不被看到RouteDefinitiondoTry/doCatch时的路线是由拦截AdviceWithRouteBuilder ,因为它们是在不同的频道。 The way to solve this is to use a mock for the endpoint and throw the exception from the mock: 解决此问题的方法是对端点使用模拟,并从模拟抛出异常:

getMockEndpoint("mock:exception").whenAnyExchangeReceived(new 
Processor() { 

            @Override 
            public void process(Exchange exchange) throws Exception { 
                throw new Exception("fail me"); 
            } 
        });

See: http://camel.465427.n5.nabble.com/question-about-exception-handling-behavior-td5743489.html 参见: http : //camel.465427.n5.nabble.com/question-about-exception-handling-behavior-td5743489.html

Also see this issue on JIRA: https://issues.apache.org/jira/browse/CAMEL-6300 It is fixed in Camel 2.10.5 and other newer versions. 另请参见JIRA上的此问题: https ://issues.apache.org/jira/browse/CAMEL-6300在Camel 2.10.5和其他更新版本中已修复。

I am not sure why this is happening to you, but I have an idea. 我不确定为什么会发生在您身上,但是我有个主意。 I am thinking that your context is starting before reaching your test case and maybe your interceptor is being set up too late. 我认为您的上下文在到达测试用例之前就已经开始,也许您的拦截器设置得太迟了。 Can you try the following? 您可以尝试以下吗?

Add this method: 添加此方法:

@Override
public boolean isUseRouteBuilder() {
    return false;
}

Then use the regular way of defining the route with context.addRoutes(new RouteBuilder(){ .. }) instead of overriding createRouteBuilder . 然后使用常规方法通过context.addRoutes(new RouteBuilder(){ .. })定义路由,而不是覆盖createRouteBuilder Also, define your interceptor here. 另外,在此处定义您的拦截器。

And after configuring your route and interceptor run context.start() in your test case. 在配置了路由和拦截器之后,在测试用例中运行context.start() Try and let me know if it worked. 尝试让我知道是否有效。

UPDATE : Overriding isUseRouteBuilder is not required. 更新 :不需要覆盖isUseRouteBuilder

UPDATE2: UPDATE2:

I have been running few tests and I am seeing the same behavior. 我已经运行了很少的测试,并且看到了相同的行为。 It seems that onException always triggers before doCatch. 似乎onException总是在doCatch之前触发。 Also, if you set handled to true the exception does not get propagated and does not reach the doCatch block. 此外,如果你设置handled ,以true异常没有得到传播,并没有达到doCatch块。

Based on the documentation of doTry doCatch doFinally I would understand the error handler does not apply ( When using doTry .. doCatch .. doFinally then the regular Camel Error Handler does not apply ) but it seems the error handler and the onException are not the same. 根据doTry doCatch doFinally的文档,我会理解错误处理程序不适用( 使用doTry .. doCatch .. doFinally时,常规的Camel错误处理程序不适用 ),但似乎错误处理程序和onException不相同。

Also, I have found this: how to handle exception or fault in multiple routes which could be helpful for you. 另外,我发现了这一点: 如何处理多条路径中的异常或错误,这可能对您有所帮助。

One last thing: you can define your interceptor in the same RouteBuilder: 最后一件事:您可以在同一RouteBuilder中定义拦截器:

    context.addRoutes(new RouteBuilder() {
        @Override
        public void configure() throws Exception {
            interceptSendToEndpoint("mock:exception").throwException(new Exception());

            onException(Exception.class).process(new Processor() {
                @Override
                public void process(Exchange exchange) throws Exception {
                    System.out.println("from onException");

                }

            }).handled(false);

            from("direct:start")
            //.errorHandler(noErrorHandler())
            .doTry()
                .to("mock:exception")
            .doCatch(Exception.class)
                .process(new Processor() {
                   @Override
                   public void process(Exchange exchange) throws Exception {
                       System.out.println("from doCatch");
                   }
                })
                .to("mock:count")
            .end();


        }
    });

Does this help? 这有帮助吗?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM