2

我一直在尝试在 Karaf 上使用 OSGi 声明式服务(以及其他东西,例如蓝图)的一些示例。我现在要解决的问题是如何在运行时获取对某些服务的引用(因此注释和/或 XML 在这里并不是一个真正的选择)

我将解释我的用例:

我正在尝试设计(到目前为止只是在我的脑海中,这就是为什么我仍然只尝试使用 OSGi :))一个系统来控制工业中的某些自动化过程。为了与设备通信,使用了一组特殊的协议。为了使组件尽可能可重用,我设计了一个基于层的通信模型(例如用于网络的 ISO/OSI 模型,但要简单得多)

要将其转换为 OSGi,我的系统的每一层都将由一组捆绑包组成。一个用于该层的接口,然后一个插件用于该层的每个实现(将其想象为 OSI 传输层上的 TCP 与 UDP)。

要引用此类网络中的任何设备,将使用自定义地址格式(此类地址的两个示例可以是 xpa://12.5/03FE 或 xpb://12.5/03FE)。这样的地址包含访问所请求设备所需的有关层及其值的所有信息。你可以猜到,这个地址的每一部分都代表了我网络模型的一层。

这些地址将存储在一些配置数据库中(因此,简单的 .cfg 或 .properties 文件也不是一个选项),以便可以在运行时远程更改它们。

我正在考虑创建一个工厂,它将解析这个地址,并根据它的所有组件,创建一个对象链(从 OSGi 获取适当的服务),实现所有层并相应地配置它们。

由于单个层可以有更多的实现(因此,实现单个接口的更多服务),这个工厂需要在运行时(当它获取作为字符串传递的设备地址时)决定选择哪个特定的实现(根据服务将声明的其他属性)。

这如何在 OSGi 中实现?什么方法更适合这个,DS、蓝图或其他方法?

4

3 回答 3

7

我意识到这是对这个问题的一个非常晚的答案,但是两个答案都错过了声明式服务中对过滤的明显内置支持。

可以使用 @Reference 注释为 DS 引用定义目标过滤器:

@Component
public class ExampleComponent {
    @Reference(target="(foo=bar)")
    MyService myService;
}

也可以使用配置添加(或覆盖)此目标过滤器。对于组件:

@Component(configurationPid="fizz.buzz")
public class ExampleComponent {
    @Reference
    MyService myService;
}

然后pid 的配置字典fizz.buzz可以使用 key 设置新的过滤器myService.target

这是一个比直接跳到原始 OSGi API 更好的选择,并且已经可用于多个规范版本。

于 2017-01-27T09:52:00.203 回答
2

我撤销我的答案,因为接受的答案是正确的。当我回答这个问题时,我错过了规范中这个很小但非常重要的细节。

OSGi 提供了一种称为服务跟踪器的好方法。您可以在声明式服务中使用。在此示例中,有一个配置包含您要使用的服务的过滤器。如果过滤器配置发生变化,整个组件将重新激活,因此跟踪机制正在重新启动。

import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Properties;
import org.apache.felix.scr.annotations.Property;
import org.osgi.framework.BundleContext;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.osgi.service.component.ComponentContext;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;

@Component(immediate = true, metatype = true)
@Properties(value = {
        @Property(name = "filterCriteria", value = "(objectClass=*)")
})
public class CustomTracker {

    private CustomServiceTracker customServiceTracker;

    @Activate
    protected void activate(ComponentContext componentContext) throws InvalidSyntaxException {
        String filterCriteria = (String) componentContext.getProperties().get("filterCriteria");
        customServiceTracker = new CustomServiceTracker(componentContext.getBundleContext(), filterCriteria);
        customServiceTracker.open(true);
    }

    @Deactivate
    protected void deactivate() {
        customServiceTracker.close();
    }

    /**
     * OSGi framework service tracker implementation. It is able to listen all serivces available in the system.
     */
    class CustomServiceTracker extends ServiceTracker {

        CustomServiceTracker(BundleContext bundleContext, String filterCriteria) throws InvalidSyntaxException {
            super(bundleContext, bundleContext.createFilter(filterCriteria), (ServiceTrackerCustomizer) null);
        }

        @SuppressWarnings("checkstyle:illegalcatch")
        @Override
        public Object addingService(ServiceReference serviceReference) {
            try {
                Object instance = super.addingService(serviceReference);
                // TODO: Whatever you need
                return instance;
            } catch (Exception e) {
                LOGGER.error("Error adding service", e);
            }
            return null;
        }

        @Override
        public void removedService(ServiceReference serviceReference, Object service) {
            // TODO: Whatever you need
            super.removedService(serviceReference, service);
        }

        @Override
        public void modifiedService(ServiceReference serviceReference,
                                    Object service) {
            super.modifiedService(serviceReference, service);
        }
    }
}
于 2015-11-22T13:47:40.850 回答
0

对于这个用例,我看到的唯一选择是直接使用 OSGi API。听起来您每次获得要处理的地址时都必须进行服务查找。因此,每次要处理地址时,您都必须获得适当的服务实现(基于过滤器)。

DS 和 Blueprint 等声明式方法无法让您执行此操作,因为过滤器无法在运行时更改。

于 2014-02-10T17:33:02.083 回答