我需要在每个配置基础上创建服务,每个服务都依赖于外部资源,因此应该管理它自己的生命周期(即(de)注册服务)。因此,将这些实现为DS并让SCR生成多个实例不起作用。
可以实现一个注册ManagedServiceFactory的bundle来完美地完成这个任务(参见my previous post)。但结果是,如果工厂依赖于其他几项服务,您需要开始跟踪这些服务并编写大量的胶水代码以使一切运行。相反,我想将工厂实现为(单例)声明性服务,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”属性是错误的路径,因为这样组件永远不会在Service Registry中注册为ManagedServiceFactory
,而是变成ComponentFactory
作为一种黑客攻击,我刚刚添加了一个组件属性,即
<property name="service.pid" type="String" value="my.project.servicefactory"/>
并添加configuration-policy="ignore"
。这样做:名为my.project.servicefactory-foobar.cfg
的配置被传递给我的服务,它在服务注册表中注册它们,一切都很好。
但是我不喜欢这两件事:
service.pid
对我来说就像是一个肮脏的黑客configuration-policy="ignore"
阻止我自己配置ManagedServiceFactory
。如果我转义此属性或将其设置为require,我将获得一个ManagedServiceFactory
用于名为my.project.servicefactory.cfg
的配置,然后为使用模式my.project.servicefactory-foobar.cfg
命名的每个配置获得两个服务:一个{{1当我们收到有关这个新配置的通知时,SCR会产生一个ManagedServiceFactory
,我的第一个ServiceInterface
会被注册。 (至少这不是指数增长,因为SCR会覆盖工厂配置的ManagedServiceFactory
属性)那么我应该如何正确设置呢?
PS:对于那些想知道我对其文件名中的配置的引用的人:我使用Felix Fileinstall进行配置,因此将service.pid
放入ConfigAdmin for PID foo.cfg
和foo
放在 factory -pid foo-bar.cfg
。
答案 0 :(得分:3)
只需使用您的DS实例无头,属性,并自行注册服务:
@Component(immedate=true, provide={}, serviceFactory=true, configurationPolicy=require)
public class Mine {
BundleContext context;
volatile ServiceRegistration r;
@Activate
void activate(BundleContext context, Map<String,Object> map) {
this.context = context;
track(map);
}
@Deactivate
void deactivate() {
if ( r != null)
r.unregisterService();
}
void track(Map<String,Object> map) {
... // do your remote stuff
r = context.registerService(...);
...
}
}
答案 1 :(得分:2)
为什么DS中的支持对您不起作用?见112.6:
Factory Configuration – If a factory PID exists, with zero or more Configurations, that is equal to the configuration PID, then for each Configuration, a component configuration must be created that will obtain additional component properties from Configuration Admin.
这表示如果组件的配置pid与CM中的工厂pid相同,那么DS将为工厂pid下的每个配置创建组件的实例。