如何使用声明式服务正确扩展 OSGi 服务?

问题描述

项目描述:

我有一个简单的 Osgi 演示项目。域是一个具有多种传感器类型的气象站。每个传感器将其数据发送到气象站。通过 API,数据通过绘图在网站上公开和可视化。

目标:

例如:我目前有三种不同的传感器类型。一种用于测量风速、温度和湿度。 气象站应该有多个风传感器实例 (Cardinality.MULTIPLE)。

现状:

目前我正在通过创建一个 WindSpeedSensor一个 WindSpeedAdvancedSensor 服务来解决这个问题。我已经为 Apache Karaf 实现了一个自定义命令,我可以在其中向我的服务发送特定的配置命令。因此,传感器可以配置为在特定范围内生成测量值。

期望条件:

最佳解决方案是通过 Karaf 命令行启动额外的 WindSpeedSensor 实例。不应该需要人工WindSpeedSensors来实现WeatherStation类的多种服务的目标。

问题:

我怎样才能做到这一点?我是 Osgi 和声明式服务的新手,我很好奇 Osgi 的专家如何解决这个问题。提前感谢您抽出宝贵时间和反馈。

解决方法

您可以使用 Factory Configurations(参见 https://docs.osgi.org/specification/osgi.cmpn/7.0.0/service.component.html#service.component-deployment)。对于出厂 pid 下的每个配置,DS 都会创建一个组件配置。这允许根据配置管理中的工厂配置多次创建一个组件。

,

我只将 OSGi 与 Karaf 一起使用,因此对于其他环境可能会有所不同。

如果您需要为每个配置文件提供 OSGi 服务,您可以使用声明性服务注释来设置此类服务,例如像这样。

import org.osgi.framework.BundleContext;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.ConfigurationPolicy;
import org.osgi.service.metatype.annotations.Designate;

import com.example.service.config.ExampleServiceConfig;

@Component(
    immediate = true,service = ExampleService.class,configurationPolicy = ConfigurationPolicy.REQUIRE,configurationPid = "com.example.service.ExampleService"
)
@Designate(ocd = ExampleServiceConfig.class,factory = true)
public class ExampleService {

    @Activate
    public void onServiceActivate(BundleContext context,ExampleServiceConfig config){
        System.out.println(config.hello_message());
    }
}

然后为服务定义类型安全的配置,例如:

import org.osgi.service.metatype.annotations.ObjectClassDefinition;

@ObjectClassDefinition(name = "ExampleService Configuration")
public @interface ExampleServiceConfig {
 
    String hello_message() default "hello world";
    String osgi_jndi_service_name() default "unique.service.name";
}

由于单例配置使用文件名,例如 <configurationPid>.cfg 工厂配置使用格式 <configurationPid>-<InstanceName>.cfg,因此要创建上面 ExampleService 的两个实例,您可以创建例如以下配置:

com.example.service.ExampleService-InstanceA.cfg

hello.message=Hello from Instance A
osgi.jdni.service.name=InstanceA

com.example.service.ExampleService-InstanceB.cfg

hello.message=Hello from Instance B
osgi.jdni.service.name=InstanceB

至少在 Karaf 中,这将创建两个 ExampleService 实例和两个具有某种唯一 guid(而不是实例名称)的配置。要引用特定的服务实例,您可以使用引用注释中的目标属性。

@Reference(
    target = "(osgi.jdni.service.name=InstanceA)"
)
ExampleService exampleService;