我有需要在每个配置基础上创建的服务,每个服务都依赖于外部资源,因此应该管理它自己的生命周期(即(取消)注册服务)。因此,将这些实现为 DS 并让 SCR 生成多个实例是行不通的。
人们可以实现一个注册 ManagedServiceFactory 的包来完美地完成此任务(请参阅我之前的帖子 https://stackoverflow.com/questions/11832204/how-do-you-implement-a-managedservicefactory-in-osgi)。但结果是,如果工厂依赖于其他几个服务,您需要开始跟踪这些服务并编写大量粘合代码以使所有内容运行。相反,我想将工厂实现为(单例)声明性服务,SCR 为其注册一个ManagedServiceFactory
在服务注册中心。
这是我的尝试:
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.cm.ConfigurationException;
import org.osgi.service.cm.ManagedServiceFactory;
import org.osgi.service.component.ComponentContext;
@SuppressWarnings({ "rawtypes", "unchecked" })
public class Factory implements ManagedServiceFactory {
private BundleContext bundleCtxt;
private Map<String, ServiceRegistration> services;
public void activate(ComponentContext context) throws Exception {
System.out.println("actiavting...");
this.bundleCtxt = context.getBundleContext();
services = new HashMap<String, ServiceRegistration>();
}
public void deactivate(ComponentContext context) {
for(ServiceRegistration reg : services.values()) {
System.out.println("deregister " + reg);
reg.unregister();
}
services.clear();
}
@Override
public String getName() {
System.out.println("returning factory name");
return "my.project.servicefactory";
}
@Override
public void updated(String pid, Dictionary properties)
throws ConfigurationException {
System.out.println("retrieved update for pid " + pid);
ServiceRegistration reg = services.get(pid);
if (reg == null) {
services.put(pid, bundleCtxt.registerService(ServiceInterface.class,
new Service(), properties));
} else {
// i should to some update here
}
}
@Override
public void deleted(String pid) {
ServiceRegistration reg = services.get(pid);
if (reg != null) {
reg.unregister();
services.remove(pid);
}
}
}
以及服务描述:
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" configuration-policy="ignore" name="my.project.servicefactory">
<implementation class="my.project.factory.Factory"/>
<service>
<provide interface="org.osgi.service.cm.ManagedServiceFactory"/>
</service>
<property name="service.pid" type="String" value="my.project.servicefactory"/>
</scr:component>
我已经发现服务描述中的“factory”属性是错误的路径,因为这样组件永远不会注册为ManagedServiceFactory
在服务注册表中,它变成了ComponentFactory
.
作为一种 hack,我只是添加了一个组件属性,即
<property name="service.pid" type="String" value="my.project.servicefactory"/>
并添加了configuration-policy="ignore"
。这有效:名为的配置my.project.servicefactory-foobar.cfg
交给我的服务,该服务将它们注册在服务注册表中,一切都很好。
但有两点我不喜欢:
- 手动设置属性
service.pid
对我来说感觉就像是一个肮脏的黑客
- setting
configuration-policy="ignore"
阻止我配置ManagedServiceFactory
它本身。如果我逃避这个属性或将其设置为需要,我会得到一个ManagedServiceFactory
对于名为my.project.servicefactory.cfg
然后为每个配置提供两个以模式命名的服务my.project.servicefactory-foobar.cfg
: one ManagedServiceFactory
SCR 产生并且一个ServiceInterface
那是我的第一个ManagedServiceFactory
当收到有关此新配置的通知时进行注册。 (至少这不会呈指数增长,因为 SCR 会覆盖service.pid
工厂配置的属性)
那么我应该如何正确设置呢?
PS:对于那些想知道我对其文件名的配置的引用的人:我使用 Felix Fileinstall 进行配置,因此foo.cfg
被放入 PID 的 ConfigAdminfoo
, and foo-bar.cfg
放在那里是为了factory-pid foo
.