如何正确使用OSGi getServiceReference()

Jen*_*ens 2 service osgi

我是OSGi的新手,并且遇到了几个关于OSGi服务的例子.

例如:

import org.osgi.framework.*;
import org.osgi.service.log.*;

public class MyActivator implements BundleActivator {
  public void start(BundleContext context) throws Exception {
    ServiceReference logRef = 
      context.getServiceReference(LogService.class.getName());
  }
}
Run Code Online (Sandbox Code Playgroud)

我的问题是,你为什么要用

getServiceReference(LogService.class.getName())
Run Code Online (Sandbox Code Playgroud)

代替

getServiceReference("LogService")
Run Code Online (Sandbox Code Playgroud)

如果使用LogService.class.getName(),则必须导入接口.这也意味着您必须在MANIFEST.MF中导入包org.osgi.services.log.

如果你想减少依赖性以推动松散耦合,那不是完全适得其反吗?据我所知,服务的一个优点是服务使用者不必知道服务发布者.但是如果你必须导入一个特定的界面,你必须知道谁在提供它.只用像"LogService"的字符串,你就不必知道该接口是由提供org.osgi.services.log.LogService.

我在这里错过了什么?

bas*_*ero 6

看起来你已经混淆了实现和界面

使用名称的实际接口(以及导入接口,您最终将完成此操作)会重新获得服务所围绕的接口合约.您不关心LogService的实现,但您确实关心接口.每个LogService都需要实现相同的接口,因此您使用接口来获取服务.大家知道,LogService实际上是一些其他bundle提供的SLF4J包装器.所有你看到的是界面.那是你正在寻找的松耦合.您不必为每个实现提供接口.保留接口它自己的bundle并拥有该接口的多个实现.

旁注:ServiceTracker通常更容易使用,试一试!

增加的好处:使用接口获取类名避免拼写错误,过多的字符串文字,并使重构更容易.

获得ServiceReference之后,接下来的几行可能会涉及到:

Object logSvc = content.getService(logRef)

// What can you do with logSvc now?!? It's an object, mostly useless

// Cast to the interface ... YES! Now you need to import it!
LogSerivce logger = (LogService)logSvc;

logger.log(LogService.LOG_INFO, "Interfaces are a contract between implementation and consumer/user");
Run Code Online (Sandbox Code Playgroud)