我正在使用 Apache-Camel 2.15.2。
我正在尝试将路由添加到 CamelContext
动态,但我遇到了一个让我困惑的问题。
据我所知,我确实将路由添加到了正确的 CamelContext
,而且似乎是他们的 configure()
被调用而不抛出异常。但是,当我尝试执行主路由时,我收到一个运行时异常,告诉我我动态添加的路由不存在。
这是我的代码的简化版本:
public class MainRouteBuilder extends RouteBuilder
{
public static CamelContext camelContext;
public static boolean returnLabel = true;
public static RouteBuilder nestedRouteBuilder;
@Override
public void configure() throws Exception
{
System.out.println("Building main route!");
System.out.println("Context: " + getContext());
camelContext = getContext();
from("direct:mainRoute")
//3. I do not actually want to instantiate RouteContainer like this each time I call this route.
//I would simply want to reuse a reference to an instance I created outside of configure()...
.to(new RouteContainer().getMyRoute(2))
;
returnLabel = false;
//configure direct:myRoute.2
includeRoutes(nestedRouteBuilder);
}
}
public class RouteContainer extends RouteBuilder
{
public Route route;
RouteContainer() {
super(MainRouteBuilder.camelContext);
}
String getMyRoute(final int n) {
if (MainRouteBuilder.returnLabel && route == null) {
route = new Route() {
@Override
public void configure()
{
System.out.println("Building nested route!");
System.out.println("Context: " + getContext());
from("direct:myRoute." + n)
.transform()
.simple("number: " + n)
.to("stream:out")
.process(new Processor() {
@Override
public void process(Exchange exchange) throws Exception {
Response response = new Response();
response.setStatus(Status.SUCCESS);
exchange.getOut().setBody(response);
}
});
}
};
}
//1. works:
MainRouteBuilder.nestedRouteBuilder = this;
//2. does not work:
// RouteContainer routeContainer = new RouteContainer();
// routeContainer.route = this.route;
// MainRouteBuilder.nestedRouteBuilder = routeContainer;
return "direct:myRoute." + n;
}
@Override
public void configure() throws Exception {
if (route != null) {
route.configure();
}
}
public abstract static class Route {
abstract public void configure();
}
}
发送到
direct:mainRoute
的请求工作。在 Camel 启动期间,我在控制台中看到:
Building main route!
Context: SpringCamelContext(camel-1) with spring id org.springframework.web.context.WebApplicationContext:/sample-route
Building nested route!
Context: SpringCamelContext(camel-1) with spring id org.springframework.web.context.WebApplicationContext:/sample-route
当我向
direct:mainRoute
发送请求时,输出为:{"status":"SUCCESS"}
但是,如果我注释掉上面的 (1) 并取消注释 (2),Camel 会以相同的输出启动到控制台,但是当我向
direct:mainRoute
发送请求时,路由执行失败,异常:org.apache.camel.component.direct.DirectConsumerNotAvailableException: No consumers available on endpoint: Endpoint[direct://myRoute.2].
澄清:我的问题是因为我实际上不想实例化
RouteContainer
每次我调用它的路由时,就像我在(3)中所做的那样。这就是为什么我在点 (2) 实例化它们并插入 Route
实例到它...所以我想
MainRouteBuilder
看起来像这样:public class MainRouteBuilder extends RouteBuilder
{
public static CamelContext camelContext;
public static boolean returnLabel = true;
public static RouteBuilder nestedRouteBuilder;
RouteContainer routeContainer = new RouteContainer();
@Override
public void configure() throws Exception
{
System.out.println("Building main route!");
System.out.println("Context: " + getContext());
camelContext = getContext();
from("direct:mainRoute")
.to(routeContainer.getMyRoute(2))
//I may want to call it again like this:
//.to(routeContainer.getMyRoute(3))
;
returnLabel = false;
//configure direct:myRoute.2
includeRoutes(nestedRouteBuilder);
}
}
我的假设是可能是嵌套路由
direct:myRoute.2
创建在错误 CamelContext
,但控制台输出告诉我事实并非如此。知道我在这里做错了什么吗?
最佳答案
路由配置 != 路由执行
您似乎将路由配置与路由执行混淆了。我们都去过那里 ;-)
当您在 MainRouteBuilder#configure()
中配置 RouteBuilder 时, 该方法仅被执行 一次 当您的 Camel 应用程序启动时,以设置路由逻辑。 DSL 为路由(处理器、拦截器等)和 创建管道。那是 路由运行时将是什么。
带回家的点: DSL 是 不是 对每个交易所一遍又一遍地执行。
换句话说,Camel 不会执行您在 (3) 中指出的操作。它不执行 new RouteContainer().getMyRoute(2)
对于每个交易所。想想看:configure()
的字节码仅在配置Camel时执行,字节码实例化一个类RouteContainer
的对象它调用 getMyRoute
带参数 2
.结果对象被送入 SendProcessor
to()
DSL 生成。
分析你的代码
现在,关于为什么您的代码没有产生您期望的结果。
您对 RouteContainer
的状态保持有问题.每次打电话getMyRoute
你覆盖了实例变量 route
.所以你当前的代码不可能调用getMyRoute
几次(不同的 n
s)然后调用 includeRoutes
最后只添加一次,因为只会添加最近生成的路由。
我也不喜欢掩盖 Camel Route
用你自己的类来上课,只是作为一个占位符,但这会带来一个你没有要求的不同的讨论。
更简单的解决方案
而不是您的 RouteContainer
类(class),这里是 RouteGenerator
创建路由并返回 direct:
的类调用者的端点。它跟踪内部 Set
中的所有路由.
public class RouteGenerator {
private Set<RouteBuilder> routeBuilders = new HashSet<>();
public String generateRoute(final int n) {
routeBuilders.add(new RouteBuilder() {
@Override public void configure() throws Exception {
System.out.println("Building nested route!");
System.out.println("Context: " + getContext());
from("direct:myRoute." + n)
.transform() .simple("number: " + n)
.to("stream:out")
.process(new Processor() {
@Override
public void process(Exchange exchange) throws Exception {
Response response = new Response();
response.setStatus(Status.SUCCESS);
exchange.getOut().setBody(response);
}
});
}
});
return "direct:myRoute." + n;
}
public Set<RouteBuilder> getRouteBuilders() {
return routeBuilders;
}
}
这是您的
MainRouteBuilder
,它实例化 RouteGenerator
只需一次,并且可以生成任意数量的路线。完成路由配置后,您只需遍历累积的
RouteBuilders
并将它们包括在内:public class MainRouteBuilder extends RouteBuilder {
public static CamelContext camelContext;
public static RouteGenerator routeGenerator = new RouteGenerator();
@Override
public void configure() throws Exception {
System.out.println("Building main route!");
System.out.println("Context: " + getContext());
camelContext = getContext();
from("direct:mainRoute")
.to(routeGenerator.generateRoute(2));
for (RouteBuilder routeBuilder : routeGenerator.getRouteBuilders()) {
includeRoutes(routeBuilder);
}
}
}
编辑:为什么您的选项 (2) 不起作用?
经过一段时间的调试,我意识到为什么你会看到这种效果。
摘自 the Java Tutorial :
As with instance methods and variables, an inner class is associated with an instance of its enclosing class and has direct access to that object's methods and fields.
在 (2) 中,您创建了一个
Route
的实例初始范围内RouteContainer
对象,充当外部对象。 Route
对象保留外部 RouteContainer
作为它的外部对象。 from()
因此,后续方法将在该 上被调用初始 RouteContainer
( RouteBuilder
) 对象,不在新的 RouteContainer
上您稍后创建 ,这是您提供给上层 RouteBuilder(与 CamelContext 相关联)的那个。这就是为什么您的
direct:myRoute.2
没有被添加到 Camel Context,因为它是在不同的路由构建器中创建的。还要注意 (2) 的控制台输出:
Building main route!
Context: CamelContext(camel-1)
Building nested route!
Context: CamelContext(camel-2)
Added!
第二条路由被添加到不同的上下文
camel-2
.这个新的上下文是由 Camel 在将路由添加到旧的 RouteBuilder 时懒惰地创建的,旧的 RouteBuilder 还没有关联到任何 Camel 上下文。注意初始RouteContainer(在实例变量初始化中创建)的Camel Context是
null
,因为您分配了 MainRouteBuilder.camelContext
以后的属性(property)。您可以通过添加以下
println
来查看如何使用两个不同的路由构建器。声明:内部路由#configure:
System.out.println("RouteContainer to which route is added: " + RouteContainer.this.hashCode());
在 MainRouteBuilder#configure 内部,就在
includeRoutes
之前:System.out.println("RouteContainer loaded into Camel: " + nestedRouteBuilder.hashCode());
对于 (1),哈希码 是一样的 .对于 (2),哈希码 不一样 ,清楚地表明有两个不同的 RouteBuilders 正在运行(一个包含路由,另一个加载到上下文中,不包含路由)。
来源:我是 Apache Camel PMC 成员和提交者。
关于java - Camel : failure to add routes dynamically,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35234605/