2014-02-20 132 views
0

我有一个提供服务的捆绑。OSGI - 捆绑服务的两个对象

我的包实施看起来是这样的:

class ServiceImpl implements Service 
    { 
     Object value; 

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

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

} 

在我的Java应用程序,我加载此包到OSGi框架,并创建两个引用到服务,企图有不同的值的两个对象“值”。

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

下面是该问题的例子:

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 

我曾经服务工厂,但它似乎不适合我的情况非常有用。我该怎么办?谢谢。

回答

0

您需要等R6。 Pre-R6,每个bundle最多可以暴露给一个服务实例。即使注册一个ServiceFactory也不会改变,因为框架会在ServiceFactory中缓存服务对象,以便在随后调用getService时返回该包。

在R6中,我们介绍service scopes,它允许服务实现将多个服务对象返回给一个包。使用它需要服务提供商和服务使用者使用R6中添加的新API。

现在你可以在Eclipse Equinox Luna中实现它。

+0

感谢。忘记参考​​服务。有没有其他方法可以让包类的两个对象具有不同的值?一些符合我需要的东西? –

+0

OSGi配置管理服务可能有用吗?每种相同服务都可以存在配置。你甚至可以在配置文件中设置'值'。 – Tony

+0

您可以使用newObject(args)等方法将您的服务设计为工厂。然后,一个客户端软件包可以获取您的服务并根据需要多次调用newObject。就像Balazs建议的那样。 –

0

即使您使用ServiceFactory,对于同一个包,也会返回相同的服务对象。 https://github.com/osgi/design/tree/master/rfcs/rfc0195

,将适合您的需要:

因为有一个关于它的RFP有可能是在未来PrototypeServiceFactory。

尽管将来可能会有一个PrototypeServiceFactory,但我认为最好是自己编程解决这个用例。例如:

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

在客户端可以使用:

BusinessLogicFactory factory = context.getService(reference); 

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

... 
+0

我在哪里可以找到BusinessLogicFactory类?它似乎不是org.osgi.framework的一部分。它是一个现有的API吗?或者你的意思是我必须做我自己的? –

+0

BusinessLogicFactory是您编写的类:)。编写一个工厂类并将其注册为OSGi服务。 –

2

两个BJ和巴拉兹提供有价值的信息,但没有解决方案,与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; 
     } 
    } 
} 
+0

谢谢。这似乎很有趣。但是我很困惑从包之外访问服务(在我的Java应用程序中)。你做的方式是ServiceTracker st1 = new ServiceTracker(context,Service.class.getName(),customizer); 但在这种情况下,我从哪里获得定制器?我应该在捆绑之外再次定义它吗? –

+0

“您可以通过第二个”工厂“界面注册您的服务,然后该工厂允许您创建该服务的实例。”:这也正是我所说的。可能还不够清楚。 –

+0

您需要在任何想要使用此服务的地方使用定制器。这个定制程序的一个鲜为人知的功能是,它允许您返回您刚查找的服务的不同定制实现。在这里我们使用它来检查实现是否是工厂,如果是,则创建一个新实例并返回该实例。这基本上就是Balazs所说的,但是试图将它从ServiceTracker中抽象出来。尽你所能,尽可能做到最好,直到新规范可用,并且您可以更好地控制范围。 –