第 294 章 Camel SCR (已弃用)

可作为 Camel 2.15 可用

SCR 代表服务组件运行时,也是 OSGi Declarative 服务规范的实现。SCR 支持任何普通旧 Java 对象公开和使用没有样板代码的 OSGi 服务。

OSGi 框架通过在捆绑包中查找 SCR 描述符文件,这些文件通常由 org.apache.felix:maven-scr-plugin 等插件从 Java 注解生成。

在 SCR 捆绑包中运行 Camel 是 Spring DM 和 Blueprint 解决方案(在您和 OSGi 框架之间大大减少代码行)的绝佳选择。使用 SCR 您的捆绑包可以在 Java 世界中保持完整状态;无需编辑 XML 或属性文件。这让您可以完全控制所有内容,意味着您选择的 IDE 准确了解项目的实际情况。

294.1. Camel SCR 支持

Camel-scr 捆绑包不包括在 2.15.0 之前的 Apache Camel 版本,但工件本身可与从 2.12.0 开始的任何 Camel 版本一起使用。

org.apache.camel/camel-scr 捆绑包提供基础类 AbstractCamelRunner,它为您管理 Camel 上下文,以及帮助程序类 ScrHelper,以用于单元测试中的 SCR 属性。Apache Karaf Camel-scr 功能定义了在 SCR 捆绑包中运行 Camel 所需的所有功能和捆绑包。

AbstractCamelRunner 类 ties CamelContext 的生命周期与服务组件的生命周期,并通过 Camel 的 PropertiesComponent 的帮助来处理配置。您只需在 java 类之外进行服务组件,从 AbstractCamelRunner 进行扩展,并在类级别添加以下 org.apache.felix.scr.annotations

添加所需的注解

@Component
@References({
    @Reference(name = "camelComponent",referenceInterface = ComponentResolver.class,
        cardinality = ReferenceCardinality.MANDATORY_MULTIPLE, policy = ReferencePolicy.DYNAMIC,
        policyOption = ReferencePolicyOption.GREEDY, bind = "gotCamelComponent", unbind = "lostCamelComponent")
})

然后,实现 getRouteBuilders () 方法,用于返回您要运行的 Camel 路由:

Implement getRouteBuilders()

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

最后,通过以下方法提供默认配置:

注解中的默认配置

@Properties({
   @Property(name = "camelContextId", value = "my-test"),
   @Property(name = "active", value = "true"),
   @Property(name = "...", value = "..."),
   ...
})

 

就是.如果使用了 camel-archetype-scr 来生成已经关注的项目。

以下是由 camel-archetype-scr 生成的完整服务组件类示例:

CamelScrExample.java

// This file was generated from org.apache.camel.archetypes/camel-archetype-scr/2.15-SNAPSHOT
package example;

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

import org.apache.camel.scr.AbstractCamelRunner;
import example.internal.CamelScrExampleRoute;
import org.apache.camel.RoutesBuilder;
import org.apache.camel.spi.ComponentResolver;
import org.apache.felix.scr.annotations.*;

@Component(label = CamelScrExample.COMPONENT_LABEL, description = CamelScrExample.COMPONENT_DESCRIPTION, immediate = true, metatype = true)
@Properties({
    @Property(name = "camelContextId", value = "camel-scr-example"),
    @Property(name = "camelRouteId", value = "foo/timer-log"),
    @Property(name = "active", value = "true"),
    @Property(name = "from", value = "timer:foo?period=5000"),
    @Property(name = "to", value = "log:foo?showHeaders=true"),
    @Property(name = "messageOk", value = "Success: {{from}} -> {{to}}"),
    @Property(name = "messageError", value = "Failure: {{from}} -> {{to}}"),
    @Property(name = "maximumRedeliveries", value = "0"),
    @Property(name = "redeliveryDelay", value = "5000"),
    @Property(name = "backOffMultiplier", value = "2"),
    @Property(name = "maximumRedeliveryDelay", value = "60000")
})
@References({
    @Reference(name = "camelComponent",referenceInterface = ComponentResolver.class,
        cardinality = ReferenceCardinality.MANDATORY_MULTIPLE, policy = ReferencePolicy.DYNAMIC,
        policyOption = ReferencePolicyOption.GREEDY, bind = "gotCamelComponent", unbind = "lostCamelComponent")
})
public class CamelScrExample extends AbstractCamelRunner {

    public static final String COMPONENT_LABEL = "example.CamelScrExample";
    public static final String COMPONENT_DESCRIPTION = "This is the description for camel-scr-example.";

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

 

CamelContextId 和 active 属性控制 CamelContext 的名称(默认为 "camel-runner-default")以及它是否启动(默认为"false")。除了这些之外,您还可以添加和使用所需很多属性。Camel 的 PropertiesComponent 处理递归属性,并在没有问题的情况下使用回退进行前缀。

AbstractCamelRunner 将使这些属性可供您的 RouteBuilder 使用,并在 Camel 的 PropertiesComponent 的帮助下将这些值注入到服务组件的名称匹配时,将这些值注入到您的 Service 组件和 RouteBuilder 字段中。这些字段可以声明任何可见性级别,并且支持许多类型(String、int、布尔值、URL、…​)。

以下是 camel-archetype-scr 生成的 RouteBuilder 类示例:

 

CamelScrExampleRoute.java

// This file was generated from org.apache.camel.archetypes/camel-archetype-scr/2.15-SNAPSHOT
package example.internal;

import org.apache.camel.LoggingLevel;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.impl.SimpleRegistry;
import org.apache.commons.lang.Validate;

public class CamelScrExampleRoute extends RouteBuilder {

    SimpleRegistry registry;

    // Configured fields
    private String camelRouteId;
    private Integer maximumRedeliveries;
    private Long redeliveryDelay;
    private Double backOffMultiplier;
    private Long maximumRedeliveryDelay;

    public CamelScrExampleRoute(final SimpleRegistry registry) {
        this.registry = registry;
    }

    @Override
    public void configure() throws Exception {
        checkProperties();

        // Add a bean to Camel context registry
        registry.put("test", "bean");

        errorHandler(defaultErrorHandler()
            .retryAttemptedLogLevel(LoggingLevel.WARN)
            .maximumRedeliveries(maximumRedeliveries)
            .redeliveryDelay(redeliveryDelay)
            .backOffMultiplier(backOffMultiplier)
            .maximumRedeliveryDelay(maximumRedeliveryDelay));

        from("{{from}}")
            .startupOrder(2)
            .routeId(camelRouteId)
            .onCompletion()
                .to("direct:processCompletion")
            .end()
            .removeHeaders("CamelHttp*")
            .to("{{to}}");


        from("direct:processCompletion")
            .startupOrder(1)
            .routeId(camelRouteId + ".completion")
            .choice()
                .when(simple("${exception} == null"))
                    .log("{{messageOk}}")
                .otherwise()
                    .log(LoggingLevel.ERROR, "{{messageError}}")
            .end();
        }
    }

    public void checkProperties() {
        Validate.notNull(camelRouteId, "camelRouteId property is not set");
        Validate.notNull(maximumRedeliveries, "maximumRedeliveries property is not set");
        Validate.notNull(redeliveryDelay, "redeliveryDelay property is not set");
        Validate.notNull(backOffMultiplier, "backOffMultiplier property is not set");
        Validate.notNull(maximumRedeliveryDelay, "maximumRedeliveryDelay property is not set");
    }
}

 

让我们更详细地了解 CamelScrExampleRoute

 

    // Configured fields
    private String camelRouteId;
    private Integer maximumRedeliveries;
    private Long redeliveryDelay;
    private Double backOffMultiplier;
    private Long maximumRedeliveryDelay;

这些字段的值通过匹配名称来设置来自属性的值。

 

        // Add a bean to Camel context registry
        registry.put("test", "bean");

如果需要为路由添加一些 Bean 到 CamelContext 的注册表,您可以执行以下操作:

 

    public void checkProperties() {
        Validate.notNull(camelRouteId, "camelRouteId property is not set");
        Validate.notNull(maximumRedeliveries, "maximumRedeliveries property is not set");
        Validate.notNull(redeliveryDelay, "redeliveryDelay property is not set");
        Validate.notNull(backOffMultiplier, "backOffMultiplier property is not set");
        Validate.notNull(maximumRedeliveryDelay, "maximumRedeliveryDelay property is not set");
    }

最好检查设置所需的参数,并在允许路由启动前有有意义的值。

 

        from("{{from}}")
            .startupOrder(2)
            .routeId(camelRouteId)
            .onCompletion()
                .to("direct:processCompletion")
            .end()
            .removeHeaders("CamelHttp*")
            .to("{{to}}");


        from("direct:processCompletion")
            .startupOrder(1)
            .routeId(camelRouteId + ".completion")
            .choice()
                .when(simple("${exception} == null"))
                    .log("{{messageOk}}")
                .otherwise()
                    .log(LoggingLevel.ERROR, "{{messageError}}")
            .end();

请注意,路由中的一切均使用属性进行配置。这基本上使您的 RouteBuilder 称为模板。SCR 允许您通过提供替代配置来创建更多路由实例。更多信息,请参阅将 Camel SCR 捆绑包用作模板