Apache Camel 4.4升级至4.8后,含Rest与Direct路由的RouteBuilder异常
Apache Camel 4.4升级至4.8后Rest与Direct路由共存时Direct路由未注册问题
问题现象
将Apache Camel从4.4版本升级到4.8版本后,出现以下异常行为:
- 同一个
RouteBuilder中同时定义Rest路由和Direct路由时,仅Rest路由被注册并启动,Direct路由未被注册 - 移除Rest路由后,Direct路由可正常注册启动
- 将Direct路由替换为Seda路由时,所有路由均能正常注册
复现测试代码
import org.apache.camel.builder.RouteBuilder; import org.apache.camel.test.junit5.CamelTestSupport; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertNotNull; public class CamelRouteTest extends CamelTestSupport { @Test public void testContext() throws Exception { context.addRoutes(new TestRouteBuilder()); context.start(); assertNotNull(context.hasEndpoint("direct:hello")); assertNotNull(context.hasEndpoint("direct:bye")); } private static class TestRouteBuilder extends RouteBuilder { @Override public void configure() { rest("/say") .get("/hello").to("direct:hello") .get("/bye").consumes("application/json").to("direct:bye") .post("/bye").to("mock:update"); from("direct:hello") .transform().constant("Hello World"); from("direct:bye") .transform().constant("Bye World"); } } }
原因分析
这是Apache Camel 4.6及以后版本的行为变更:当Rest DSL中引用Direct端点时,Camel对Direct端点的生命周期管理做了优化。默认情况下,若Direct端点仅被Rest路由作为生产者引用,且对应的消费者路由在同一个RouteBuilder中,会出现消费者路由未被正确注册的情况。而Seda路由不受此影响,因为Seda的端点生命周期管理逻辑与Direct不同。
解决方案
提供两种可行的解决方法:
方法一:拆分路由到不同的RouteBuilder
将Rest路由和Direct路由分别放在独立的RouteBuilder中,再依次添加到Camel上下文:
// Rest路由单独的RouteBuilder private static class RestRouteBuilder extends RouteBuilder { @Override public void configure() { rest("/say") .get("/hello").to("direct:hello") .get("/bye").consumes("application/json").to("direct:bye") .post("/bye").to("mock:update"); } } // Direct路由单独的RouteBuilder private static class DirectRouteBuilder extends RouteBuilder { @Override public void configure() { from("direct:hello") .transform().constant("Hello World"); from("direct:bye") .transform().constant("Bye World"); } } // 测试方法中添加两个路由 @Test public void testContext() throws Exception { context.addRoutes(new RestRouteBuilder()); context.addRoutes(new DirectRouteBuilder()); context.start(); assertNotNull(context.hasEndpoint("direct:hello")); assertNotNull(context.hasEndpoint("direct:bye")); }
方法二:显式设置Direct路由的自动启动属性
在Direct路由上显式添加autoStartup(true)配置,确保路由被强制注册启动:
from("direct:hello") .autoStartup(true) .transform().constant("Hello World"); from("direct:bye") .autoStartup(true) .transform().constant("Bye World");
验证说明
采用上述任意一种方法后,重新运行测试,direct:hello和direct:bye端点将被正常注册,测试断言通过。
内容的提问来源于stack exchange,提问作者Bob Wernsman
相关产品推荐
相关产品推荐

