我有一个提供服务的软件包。
我的捆绑包实现如下:
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,但它似乎对我的情况没用。我该怎么办?感谢。
答案 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();
...