第 295 章 Camel SCR (已弃用)


从 Camel 2.15 开始提供

SCR 代表服务组件运行时,是 OSGi Declarative Services 规格的实施。SCR 允许任何普通旧 Java 对象公开和使用没有样板代码的 OSGi 服务。

OSGi 框架通过查看其捆绑包中的 SCR 描述符文件来知道您的对象,这些文件通常是通过 org.apache.felix:maven-scr-plugin 等 Java 注解生成的。

在 SCR 捆绑包中运行 Camel 是 Spring DM 和 Blueprint 基于蓝图的解决方案,你和 OSGi 框架之间代码行要少得多。使用 SCR 您的捆绑包可在 Java 世界中完全保留;无需编辑 XML 或属性文件。这可让您完全控制一切,这意味着您选择的 IDE 知道您的项目中的具体内容。

295.1. Camel SCR 支持

camel-scr 捆绑包没有包括在 Apache Camel 之前的版本 2.15.0 中,但工件本身可以从 2.12.0 开始用于任何 Camel 版本。

org.apache.camel/camel-scr 捆绑包提供基本类 AbstractCamelRunner,它管理您和帮助程序类 ScrHelper,用于在单元测试中使用 SCR 属性。Camel-scr 功能可用于定义在 SCR 捆绑包中运行 Camel 所需的所有功能和捆绑包。

AbstractCamelRunner 类将 CamelContext 的生命周期与 Service 组件的生命周期相关联,并使用 Camel 的 PropertiesComponent 来处理配置。从 java 类中使一个 Service 组件从 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")
})
Copy to Clipboard Toggle word wrap

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

实施 getRouteBuilders ()

    @Override
    protected List<RoutesBuilder> getRouteBuilders() {
        List<RoutesBuilder> routesBuilders = new ArrayList<>();
        routesBuilders.add(new YourRouteBuilderHere(registry));
        routesBuilders.add(new AnotherRouteBuilderHere(registry));
        return routesBuilders;
    }
Copy to Clipboard Toggle word wrap

最后提供默认配置:

注解中的默认配置

@Properties({
   @Property(name = "camelContextId", value = "my-test"),
   @Property(name = "active", value = "true"),
   @Property(name = "...", value = "..."),
   ...
})
Copy to Clipboard Toggle word wrap

这一切。并且如果您使用 camel-archetype-scr 来生成一个项目,则这已经需要注意。

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

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;
    }
}
Copy to Clipboard Toggle word wrap

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

AbstractCamelRunner 将为您的 RouteBuilders 提供这些属性,并提供 Camel 的 PropertiesComponents,它还会在名称匹配时将这些值注入到您的 Service 组件和 RouteBuilder 字段中。可以使用任何可见性级别声明字段,并且支持许多类型(字符串、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");
    }
}
Copy to Clipboard Toggle word wrap

让我们一起查看 CamelScrExampleRoute

    // Configured fields
    private String camelRouteId;
    private Integer maximumRedeliveries;
    private Long redeliveryDelay;
    private Double backOffMultiplier;
    private Long maximumRedeliveryDelay;
Copy to Clipboard Toggle word wrap

这些字段的值通过匹配其名称来使用来自属性的值。

        // Add a bean to Camel context registry
        registry.put("test", "bean");
Copy to Clipboard Toggle word wrap

如果需要将一些 Bean 添加到 CamelContext 的 registry 中用于路由,您可以执行以下操作:

    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");
    }
Copy to Clipboard Toggle word wrap

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

        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();
Copy to Clipboard Toggle word wrap

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

返回顶部
Red Hat logoGithubredditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

通过我们的产品和服务,以及可以信赖的内容,帮助红帽用户创新并实现他们的目标。 了解我们当前的更新.

让开源更具包容性

红帽致力于替换我们的代码、文档和 Web 属性中存在问题的语言。欲了解更多详情,请参阅红帽博客.

關於紅帽

我们提供强化的解决方案,使企业能够更轻松地跨平台和环境(从核心数据中心到网络边缘)工作。

Theme

© 2025 Red Hat