如果路由生成器包含错误处理程序,Camel SCR 组件会尝试将组件添加到上下文两次

Camel SCR component tries to add component to context twice if route builder includes an errorHandler

我在 Karaf 中使用 Camel,使用 SCR 处理来自 ActiveMQ 的消息

版本:

当我将以下 Camel 路由部署到 Karaf 时一切正常:

package com.test;
import org.apache.camel.builder.RouteBuilder;

public class TestRoute extends RouteBuilder {
    @Override
    public void configure() throws Exception {

        from("activemq:queue:TEST.IN")
        .routeId("test-route")
        .log("Message picked up from IN queue");
    }
}

这是我的 SCR Runner class:

package com.test;

import java.util.ArrayList;
import java.util.List;

import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.camel.component.ActiveMQComponent;
import org.apache.activemq.pool.PooledConnectionFactory;
import org.apache.camel.RoutesBuilder;
import org.apache.camel.component.jms.JmsConfiguration;
import org.apache.camel.scr.AbstractCamelRunner;
import org.apache.camel.spi.ComponentResolver;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Properties;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.ReferencePolicy;
import org.apache.felix.scr.annotations.ReferencePolicyOption;
import org.apache.felix.scr.annotations.References;
import org.osgi.framework.BundleContext;

@Component(label = TestRunner.COMPONENT_LABEL, description = TestRunner.COMPONENT_DESCRIPTION, immediate = true, metatype = true)
@Properties({
    @Property(name = "camelContextId", value = "test-context"),
    @Property(name = "active", value = "true"),
})
@References({
    @Reference(name = "camelComponent",referenceInterface = ComponentResolver.class,
        cardinality = ReferenceCardinality.MANDATORY_MULTIPLE, policy = ReferencePolicy.DYNAMIC,
        policyOption = ReferencePolicyOption.GREEDY, bind = "gotCamelComponent", unbind = "lostCamelComponent")
})
public class TestRunner extends AbstractCamelRunner {

    public static final String COMPONENT_LABEL = "TestRunner";
    public static final String COMPONENT_DESCRIPTION = "This is the description for the test runner";

    @Override
    protected List<RoutesBuilder> getRouteBuilders() {
        List<RoutesBuilder> routesBuilders = new ArrayList<RoutesBuilder>();
        routesBuilders.add(new TestRoute());
        return routesBuilders;
    }

    @Override
    protected void setupCamelContext(BundleContext bundleContext, String camelContextId)throws Exception{
        super.setupCamelContext(bundleContext, camelContextId);

        // Add Active MQ connection factory
        ActiveMQConnectionFactory amqConnectionFactory = new ActiveMQConnectionFactory("tcp://c3m-activemq:61616");
        amqConnectionFactory.setUserName("admin");
        amqConnectionFactory.setPassword("admin");

        // Create Pooled Connection Factory
        PooledConnectionFactory amqPooledConnectionFactory = new PooledConnectionFactory(amqConnectionFactory);
        amqPooledConnectionFactory.setMaxConnections(5);
        amqPooledConnectionFactory.setMaximumActiveSessionPerConnection(5);

        // Create JMS Configuration
        JmsConfiguration consumerJmsConfig = new JmsConfiguration(amqPooledConnectionFactory);
        consumerJmsConfig.setConcurrentConsumers(5);

        // Create the ActiveMQ Component
        ActiveMQComponent activemq = ActiveMQComponent.activeMQComponent();
        activemq.setConfiguration(consumerJmsConfig);

        // Add activeMQ component to the Camel Context
        getContext().addComponent("activemq", activemq);            

        // Use MDC logging
        getContext().setUseMDCLogging(true);

        // Use breadcrumb logging
        getContext().setUseBreadcrumb(true);
    }
}

但是,如果我将 errorHandler 添加到我的 routeBuilder,那么事情就会失败。

这是添加了 errorHandler 的相同路由:

public void configure() throws Exception {
    errorHandler(deadLetterChannel("activemq:queue:TEST.DLQ").useOriginalMessage());

    from("activemq:queue:TEST.IN")
    .routeId("test-route")
    .log("Message picked up from IN queue");
}

发生了什么: - 在 Karaf 上安装包时出现以下错误:

2016-12-20 09:49:58,248 |错误 | nsole 用户 karaf |路由器 | 124 - com.test.router - 1.1.0.SNAPSHOT | [com.test.TestRunner(7)] 激活方法抛出异常 java.lang.IllegalArgumentException:无法添加组件,因为它之前已经添加过:activemq 在 org.apache.camel.impl.DefaultCamelContext.addComponent(DefaultCamelContext.java:369) 在 com.test.TestRunner.setupCamelContext(TestRunner.java:75)[124:com.test.router:1.1.0.SNAPSHOT] 在 org.apache.camel.scr.AbstractCamelRunner.prepare(AbstractCamelRunner.java:90)[72:org.apache.camel.camel-scr:2.16.0] 在 org.apache.camel.scr.AbstractCamelRunner.activate(AbstractCamelRunner.java:79)[72:org.apache.camel.camel-scr:2.16.0] ...

然后 Camel 路由没有部署在 Karaf。

我将继续进行更多故障排除,但也许有人更充分地了解这里出了什么问题

在你自己的 TestRunner class 然后只添加组件,如果它还没有注册,你可以使用

if (context.hasComponent("activemq") != null) {
  ... add component
}

最后我用下面的 hack 解决了这个问题:如果组件已经存在,我先删除它然后再添加回来。

代码如下:

// If activemq component already exists, remove it
// Note: This is a bit of a hack, but if we keep the one that is there
// Camel throws a security exception.
if (getContext().hasComponent("activemq") != null) {
    getContext().removeComponent("activemq");
}

// Create the ActiveMQ Component
ActiveMQComponent activemq = ActiveMQComponent.activeMQComponent();
activemq.setConfiguration(consumerJmsConfig);
getContext().addComponent("activemq", activemq);

不漂亮,但如果我不删除它并部署路由,camel 会给出安全异常,几乎就像现有组件 "lost" 代理的凭据一样。

感谢克劳斯的帮助!