【问题标题】:How to create multiple instances of osgi service without using DS annotations如何在不使用 DS 注释的情况下创建 osgi 服务的多个实例
【发布时间】:2019-03-11 04:48:04
【问题描述】:

我创建了一个 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 做到这一点?

【问题讨论】:

    标签: java osgi osgi-ds


    【解决方案1】:

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

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

    【讨论】:

    • 我不能使用 DS 1.3,因为我们使用的 Equinox 版本不支持它。您知道如何使用 DS 1.2 实现它
    • 您不能使用 DS 1.2。
    【解决方案2】:

    在我看来,这看起来像是根据您认为的答案而不是描述您想要达到的目标提出问题。如果我们退后几步,则存在更优雅的解决方案。

    一般来说,将对象注入有状态服务是 OSGi 中的一种不良模式。它迫使您对生命周期非常小心,并冒着内存泄漏的风险。从示例代码看来,您真正想要的是让您的消费者在事件管理主题上发生事件时得到通知。最简单的方法是从等式中删除 XyzHandler 并使消费者成为这样的事件处理程序:

    @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,那么将消费者注册为服务并使用白板模式让单个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,并且会使您的代码更加简洁。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-10-01
      • 2020-07-18
      • 1970-01-01
      • 2016-03-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多