OSGI - 捆绑服务的两个对象

时间:2014-02-20 17:19:12

标签: service reference osgi bundle

我有一个提供服务的软件包。

我的捆绑包实现如下:

    class ServiceImpl implements Service
    {
      Object value;

      @Override
      public void setValue(Object value)
      {
         this.value = value;
      }

      @Override
      public Object getValue()
      {
       return value;
      }

}

在我的java应用程序中,我将此包加载到OSGI框架,并创建对该服务的两个引用,试图让两个对象具有不同的“value”值。

不幸的是,这似乎不起作用。该服务始终返回由任一对象设置的最后一个值。我怎样才能克服这个问题?

以下是此问题的示例:

Service object1 = context.getService(reference1);
Service object2 = context.getService(reference2);

Integer one= 1;
Integer two =2;

object1.setValue(1);
object2.setValue(2);

System.out.println(object1.getValue() ); //returns 2 !!!!!!!!!!!!!!!!!!
System.out.println(object2.getValue() ); //returns 2 

我使用了ServiceFactory,但它似乎对我的情况没用。我该怎么办?感谢。

3 个答案:

答案 0 :(得分:2)

BJ和Balazs都提供了有价值的信息,但没有适用于OSGi规范当前版本的解决方案。

您可以使用第二个“工厂”界面注册您的服务。然后,该工厂允许您创建服务的实例。因为您可能不希望手动执行此操作,所以可以在ServiceTracker中隐藏此逻辑。

这种方法有一些“缺点”。首先,您需要注册服务并让实例同时实现Factory和Service。其次,您始终必须使用此自定义ServiceTracker来访问它。如果使用允许扩展其依赖项的依赖项管理器(例如Apache Felix依赖项管理器),则可以在自定义ServiceDependency中轻松隐藏所有这些。

无论如何,为了向您展示这确实有效,这是一个简单的例子:

public class Activator implements BundleActivator {
    @Override
    public void start(final BundleContext context) throws Exception {
        context.registerService(Service.class.getName(), new FactoryImpl(), null);

        ServiceTrackerCustomizer customizer = new ServiceTrackerCustomizer() {
            @Override
            public Object addingService(ServiceReference reference) {
                Object service = context.getService(reference);
                if (service instanceof Factory) {
                    return ((Factory) service).createInstance();
                }
                return service;
            }

            @Override
            public void modifiedService(ServiceReference reference,
                    Object service) {
                // TODO Auto-generated method stub
            }

            @Override
            public void removedService(ServiceReference reference,
                    Object service) {
                // TODO Auto-generated method stub
            }
        };
        ServiceTracker st1 = new ServiceTracker(context, Service.class.getName(), customizer);
        ServiceTracker st2 = new ServiceTracker(context, Service.class.getName(), customizer);

        st1.open();
        st2.open();

        Service s1 = (Service) st1.getService();
        Service s2 = (Service) st2.getService();

        s1.setValue("test1");
        s2.setValue("test2");
        System.out.println(s1.getValue());
        System.out.println(s2.getValue());
    }

    @Override
    public void stop(BundleContext context) throws Exception {
    }

    static interface Factory {
        public Object createInstance();
    }

    static class FactoryImpl extends ServiceImpl implements Factory, Service {
        @Override
        public Object createInstance() {
            return new ServiceImpl();
        }
    }

    static interface Service {
        public void setValue(Object value);
        public Object getValue();
    }

    static class ServiceImpl implements Service {
        private Object m_value;

        @Override
        public void setValue(Object value) {
            m_value = value;
        }

        @Override
        public Object getValue() {
            return m_value;
        }
    }
}

答案 1 :(得分:0)

你需要等待R6。在R6之前,每个捆绑包最多只能暴露一个服务实例。即使注册ServiceFactory也不会改变,因为框架将从ServiceFactory缓存服务对象,以便在后续调用getService时返回到bundle。

在R6中,我们引入了service scopes,它允许服务实现将多个服务对象返回到bundle。使用此方法需要服务提供者和服务使用者使用在R6中添加的新API。

现在,您可以在Eclipse Equinox Luna中实现它。

答案 2 :(得分:0)

即使您使用ServiceFactory,对于同一个捆绑包也会返回相同的服务对象。

将来可能会有一个PrototypeServiceFactory,因为有关于它的RFP:https://github.com/osgi/design/tree/master/rfcs/rfc0195

这符合您的需求。

虽然将来可能会有一个PrototypeServiceFactory,但我认为最好以编程方式自行解决这个用例。 E.g:

而不是创建可变的OSGi服务(我不认为创建可变服务是一个好主意)创建一个工厂。

在客户端,您将使用:

BusinessLogicFactory factory = context.getService(reference);

BusinessLogic object1 = factory.createInstance();
BusinessLogic object2 = factory.createInstance();

...