在 OSGi 中,被跟踪的服务类型和被跟踪对象的类型有什么区别

In OSGi, what is the difference between type of service being tracked and type of the tracked object

在 OSGi 中 class ServiceTracker 定义了两个类型参数:

  1. S - 被跟踪的服务类型。
  2. T - 跟踪对象的类型。

两者有什么区别?

被跟踪的对象允许您在再次删除服务时进行任何必要的内务处理。

示例见 trackers in pax-jdbc。在这种情况下,我们需要两个服务。 PooledDataSourceFactoryTracker 将为 DataSourceFactory 启动另一个跟踪器。第二个跟踪器是第一个跟踪器的跟踪对象。当再次删除 PooledDataSourceFactory 时,另一个 DataSourceFactory 跟踪器也将关闭。

这种方法允许跟踪多个服务或在服务删除时进行其他内务处理,而无需处理线程。

请注意,即使使用这种方法,服务跟踪器也很难正确使用。在大多数情况下,最好从一开始就使用声明式服务等框架。

T 允许您跟踪与该服务类型 S 不同的类型。例如,您可以将服务 S 包装在类型 T 的对象中。对于大多数用例,ST 是相同的。但是有些用例 T != S.

在几乎所有情况下,我都使用服务跟踪器,我需要做一些与跟踪对象相关的内务处理。当被跟踪的对象消失时,该管理信息应该被垃圾收集。

例如,您跟踪 WhiteboardListeners。但是,您想要跟踪他们使用了多长时间的回叫,并在他们使用太多时间时拒绝为他们提供服务。所以我们创建一个包装器:

public class Example {

  interface Whiteboard {
    void visit();
  }

  static class Wrapper {
    Whiteboard  whiteboard;
    AtomicLong  averageTime = new AtomicLong();

    public Wrapper(Whiteboard whiteboard) {
        this.whiteboard = whiteboard;
    }

    void visit() {
        if (averageTime.get() < 100) {
            long start = System.currentTimeMillis();
            whiteboard.visit();
            long time = System.currentTimeMillis() - start;
            averageTime.getAndUpdate(v -> (99 * v + time) / 100);
        } else
            averageTime.getAndUpdate(v -> (99 * v) / 100);
    }
  }

  ServiceTracker<Whiteboard, Wrapper> tracker;

  @Activate
  void activate(BundleContext context) {
      tracker = new ServiceTracker<Whiteboard, Wrapper>(context,
            Whiteboard.class, null) {
        @Override
        public Wrapper addingService(
                ServiceReference<Whiteboard> reference) {
            return new Wrapper(context.getService(reference));
        }

        @Override
        public void removedService(ServiceReference<Whiteboard> reference,
                Wrapper service) {
            context.ungetService(reference);
        }
    };
    tracker.open();
  }

  void visit() {
    tracker.getTracked().values().forEach(wrapper -> wrapper.visit());
  }
}

我现在很少使用 Service Tracker,因为声明式服务在大多数情况下更容易完成这项工作。但是,当我使用 Service Tracker 时,我很少遇到 S==T.