如何在不使用DS批注的情况下创建osgi服务的多个实例

时间:2018-10-05 16:15:19

标签: java osgi osgi-ds

我创建了一个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;
  }
}

在我的消费者类中,我想访问XyzHandler的服务实例并设置属性消费者。我也想每次为每个请求创建一个新的XyzHandler服务实例。 我发现很少有文章提到使用osgi声明式服务注释可以实现此目的。 OSGi how to run mutliple instances of one service

但是我想在不使用DS 1.3的情况下实现这一目标。

如何在不使用注释的情况下执行此操作,或者如何使用DS 1.2进行操作?

2 个答案:

答案 0 :(得分:1)

在我看来,这似乎是根据您认为答案是什么而不是描述您要达到的目标来提出问题的情况。如果我们往后走几步,则存在一个更优雅的解决方案。

通常,将对象注入有状态服务是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的情况,并且可以使您的代码更加整洁。

答案 1 :(得分:0)

听起来您的服务需要是prototype scope service。这是在Core R6中引入的。来自Compendium R6的DS 1.3包含对要成为prototype scope services的组件的支持。

但是DS 1.2早于Core R6,因此不了解或不支持原型范围服务。