Osgi ConfigurationAdmin延迟激活组件

时间:2018-12-06 13:49:46

标签: osgi declarative-services

我有一项需要配置的服务

@Component(service=InstrumenterService.class ,configurationPid = "InstrumenterService", configurationPolicy = ConfigurationPolicy.REQUIRE, scope = ServiceScope.PROTOTYPE)
public class InstrumenterService

此服务在另一个服务中被引用:

@Component(service = SampleService.class, scope = ServiceScope.PROTOTYPE)
public class SampleService {

    @Reference(cardinality = ReferenceCardinality.OPTIONAL, scope = ReferenceScope.PROTOTYPE_REQUIRED, policyOption = ReferencePolicyOption.GREEDY)
    InstrumenterService coverageInstrumenter;

    public boolean hasInstrumenter() {
        if(coverageInstrumenter == null)
            return false;
        return true;
    }
}

此SampleService在挂钩到主要osgi线程的Main类内使用。 我要使用ComponentServiceObjects来创建按需SampleServices。

@Component(immediate = true, property = "main.thread=true")
public class Main implements Runnable {

    @Reference
    ConfigurationAdmin cfgAdm;

    @Reference(scope = ReferenceScope.PROTOTYPE_REQUIRED)
    private ComponentServiceObjects<SampleService> sampleServices;

    public void run() {
        if (cfgAdm != null) {
            Configuration configuration;
            try {
                configuration = cfgAdm.getConfiguration("InstrumenterService", "?");
                Hashtable<String, Object> props = new Hashtable<>();
                props.put("some_prop", "some_value");
                configuration.update(props);
            } catch (IOException e1) {
                e1.printStackTrace();
            }
        }

        SampleService servicess = sampleServices.getService();
        System.out.println(servicess.hasInstrumenter());
    }
}

我遇到的问题是,除非我放置Thread.sleep(500),否则在InstrumenterService中看不到ConfigurationAdmin设置的配置。调用configuration.update之后的命令。

使用Thread.sleep命令确保配置更新是可见的,我对此并不十分满意。 是否有API可以检查配置是否已更新并且可以使用?

感谢Neil,我找到了可行的解决方案。 配置设置为等待服务后,我使用了ServiceTracker:

        BundleContext bundleContext = FrameworkUtil.getBundle(getClass()).getBundleContext();
    ServiceTracker serviceTracker = new ServiceTracker(bundleContext, InstrumenterService.class.getName(), null);

    serviceTracker.open();
    try {
        serviceTracker.waitForService(500);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    serviceTracker.close();

首先需要ConfigurationAdmin的原因是因为有一个IInstrumenter接口,可以由许多不同的类实现。 该仪器的名称在ConfigurationAdmin中设置,然后在其他服务中进一步“自动”获取所需的仪器服务。

通过这种方式,可以将任意数量的仪器添加到应用程序中,只需知道仪器的名称即可使用它。

我还要提及的是,通过OSGI,我们设法将整体式旧应用程序划分为更多模块(〜15个),它们之间并不直接依赖,而是使用API​​层。

再次感谢您使用OSGI所做的出色工作。

1 个答案:

答案 0 :(得分:0)

正如注释中所阐明的,此代码并不完全现实。在生产代码中,通常不需要更新配置记录,然后立即获取组件发布的服务。这是因为任何此类代码都对配置更新的效果做出了太多假设。

getServiceReferencegetService的调用仅在特定时刻返回服务注册表状态的快照。调用getService期望它返回一个值本质上是不可靠的。

实际上,我们总是使用一种模式,在这种情况下,我们会响应通知服务存在的情况。这可以通过多种方式完成,包括ServiceListenerServiceTracker,但是最简单的方法是编写一个带有引用的组件,例如:

@Component
public class MyComponent {
    @Reference
    SampleService service;

    public void doSomething() {
        println(service.hasInstrumenter());
    }
}

此组件具有对SampleService的强制性引用,并且仅在SampleService的实例可用时才会激活。