java - Camel : failure to add routes dynamically

标签 java apache-camel tomcat7 java-7

我正在使用 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(与 Ca​​melContext 相关联)的那个。

这就是为什么您的 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/

相关文章:

java - 如何在android studio的MainActivity.java中加载静态库(libtest.a)

java - Camel 中是否有任何组件可以运行独立路由?

Tomcat 7 上下文路径和 war 文件名

java - 使用 Java Sound API 通过 UDP 发送语音

java - Debug模式下的断点不适用于 jhipster

java - 东部夏令时间还是东部夏令时间?根据夏令时动态设置 3 个字母时区

java - 如何在KURA框架中配置apache CAMEL

java - Camel ReSTLet - 如何使用 SSL 公开服务

java - nginx tomcat7错误: - “recv() failed (104: Connection reset by peer) while reading response header from upstream”

java - Struts2 教程在 .action 页面上给出 404