我已经创建了一个Osgi服务。每当服务请求到达时,我都想创建一个新的服务实例。
代码看起来像这样-
@Component(immediate=true)
@Service(serviceFactory = true)
@Property(name = EventConstants.EVENT_TOPIC, value = {DEPLOY, UNDEPLOY })
public class XyzHandler implements EventHandler {
private Consumer consumer;
public static setConsumer(Consumer consumer) {
this.consumer = consumer;
}
@Override
public void handleEvent(final Event event) {
consumer.notify();
}
}
public class Consumer {
private DataSourceCache cache;
public void notify() {
updateCache(cache);
System.out.println("cache updated");
}
public void updateCache(DataSourceCache cache) {
cache = null;
}
}
在我的Consumer类中,我想访问XyzHandler的服务实例并设置属性Consumer。我也想每次为每个请求创建一个新的XyzHandler服务实例。
我发现很少有文章提到使用osgi声明式服务注释可以实现这一点。
OSGi how to run mutliple instances of one service
但我想在不使用DS 1.3的情况下实现这一目标。
如何在不使用注释的情况下执行此操作,或者如何使用DS 1.2进行操作?
最佳答案
对我来说,这似乎是根据您认为答案是什么而不是描述您要达到的目标提出问题的情况。如果我们往后走几步,则存在一个更优雅的解决方案。
通常,将对象注入有状态服务是OSGi中的一种不良模式。它迫使您在生命周期上要格外小心,并存在内存泄漏的风险。在示例代码中,似乎在事件管理主题上发生事件时,您真正想要的是让您的消费者得到通知。最简单的方法是从等式中删除XyzHandler,并使Consumer成为如下事件处理程序:
@Component(property= { EventConstants.EVENT_TOPIC + "=" + DEPLOY,
EventConstants.EVENT_TOPIC + "=" + UNDEPLOY})
public class Consumer implements EventHandler {
private DataSourceCache cache;
@Override
public void handleEvent(final Event event) {
notify();
}
public void notify() {
updateCache(cache);
System.out.println("cache updated");
}
public void updateCache(DataSourceCache cache) {
cache = null;
}
}
如果您确实不希望将
Consumer
设置为EventHandler
,那么将Consumer作为服务注册并使用白板模式将其由单个XyzHandler
接收仍然会更容易:@Component(service=Consumer.class)
public class Consumer {
private DataSourceCache cache;
public void notify() {
updateCache(cache);
System.out.println("cache updated");
}
public void updateCache(DataSourceCache cache) {
cache = null;
}
}
@Component(property= { EventConstants.EVENT_TOPIC + "=" + DEPLOY,
EventConstants.EVENT_TOPIC + "=" + UNDEPLOY})
public class XyzHandler implements EventHandler {
// Use a thread safe list for dynamic references!
private List<Consumer> consumers = new CopyOnWriteArrayList<>();
@Reference(cardinality=MULTIPLE, policy=DYNAMIC)
void addConsumer(Consumer consumer) {
consumers.add(consumer);
}
void removeConsumer(Consumer consumer) {
consumers.remove(consumer);
}
@Override
public void handleEvent(final Event event) {
consumers.forEach(this::notify);
}
private void notify(Consumer consumer) {
try {
consumer.notify();
} catch (Exception e) {
// TODO log this?
}
}
}
以这种方式使用白板模式可避免您需要跟踪在捆绑包启动或停止时需要创建/销毁哪个
XyzHandler
的情况,从而使您的代码更加整洁。