我是 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());
}
}
我的问题是,为什么你使用
getServiceReference(LogService.class.getName())
而不是
getServiceReference("LogService")
如果你使用LogService.class.getName(),你必须导入接口。这也意味着您必须在 MANIFEST.MF 中导入包org.osgi.services.log。
如果您想减少依赖关系以推动松散耦合,这不是完全适得其反吗?据我所知,服务的优点之一是服务使用者不必知道服务发布者。但如果您必须导入一个特定的接口,您显然必须知道谁提供它。通过仅使用像“LogService”这样的字符串,您不必知道该接口是由org.osgi.services.log.LogService提供的。
我在这里缺少什么?
I am new to OSGi and came across several examples about OSGi services.
For example:
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());
}
}
My question is, why do you use
getServiceReference(LogService.class.getName())
instead of
getServiceReference("LogService")
If you use LogService.class.getName() you have to import the Interface. This also means that you have to import the package org.osgi.services.log in your MANIFEST.MF.
Isn't that completely counterproductive if you want to reduce dependencies to push loose coupling? As far as I know one advantage of services is that the service consumer doesn't have to know the service publisher. But if you have to import one specific Interface you clearly have to know who's providing it. By only using a string like "LogService" you would not have to know that the Interface is provided by org.osgi.services.log.LogService.
What am I missing here?
发布评论
评论(4)
看起来您已经混淆了实现和接口。
使用实际的接口作为名称(并导入接口,无论如何您最终都会这样做)强化了服务设计所围绕的接口契约。您不关心 LogService 的实现,但您关心接口。每个 LogService 都需要实现相同的接口,因此您可以使用该接口来获取服务。就您所知,LogService 实际上是由其他捆绑包提供的 SLF4J 的包装器。你看到的只是界面。这就是您正在寻找的松散耦合。您不必在每个实现中都附带接口。将接口保留为自己的包,并拥有该接口的多个实现。
旁注:ServiceTracker 通常更容易使用,尝试一下!
额外的好处:使用接口获取类名可以避免拼写错误、过多的字符串文字,并使重构变得更加容易。
获得 ServiceReference 后,接下来的几行可能会涉及到以下内容:
Looks like you've confused implementation and interface
Using the actual interface for the name (and importing the interface , which you'll end up doing anyway) reenforces the interface contract that services are designed around. You don't care about the implemenation of a LogService but you do care about the interface. Every LogService will need to implement the same interface, hence your use of the interface to get the service. For all you know the LogService is really a wrapper around SLF4J provided by some other bundle. All you see is the interface. That's the loose coupling you're looking for. You don't have to ship the interface with every implementation. Leave the interface it's own bundle and have multiple implementations of that interface.
Side note: ServiceTracker is usually easier to use, give it a try!
Added benefits: Using the interface get the class name avoids spelling mistakes, excessive string literals, and makes refactoring much easier.
After you've gotten the ServiceReference, your next couple lines will likely involve this:
如果您使用 LogService,那么无论如何您都会耦合到它。如果您编写中间件,您可能会通过某些 XML 文件或 API 获得参数化的名称。是的,“LogService”会严重失败,您需要使用完全限定名称:“org.osgi.service.log.LogService”。使用 LogService.class.getName() 模式的主要原因是在重构代码时获得正确的重命名并最大限度地减少拼写错误。下一个 OSGi API 很可能会有:
提高类型安全性的调用。
不管怎样,除非你开发中间件,否则我永远不会使用这些低级 API。如果您实际上依赖于具体的类 DS 则无限简单,当您将其与 bnd 注释一起使用时甚至更简单 (http://enroute.osgi.org/doc/217-ds.html)。
如果您开发中间件,您通常会通过字符串或类对象获取服务类,而无需知道实际的类。在这些情况下使用基于字符串的 OSGi API,因为它允许我们更加懒惰,直到最后一刻才创建类加载器。我认为 12 年前我们在 OSGi 中犯的最大错误就是没有将 DS 概念纳入核心......:-(
If you use the LogService, you're coupled to it anyway. If you write middleware you likely get the name parameterized through some XML file or via an API. And yes, "LogService" will fail terribly, you need to use the fully qualified name: "org.osgi.service.log.LogService". Main reason to use the LogService.class.getName() pattern is to get correct renaming when you refactor your code and minimize spelling errors. The next OSGi API will very likely have:
calls to increase type safety.
Anyway, I would never use these low level API unless you develop middleware. If you actually depend on a concrete class DS is infinitely simpler, and even more when you use it with the bnd annotations (http://enroute.osgi.org/doc/217-ds.html).
If you develop middleware you get the service classes usually without knowing the actual class, via a string or class object. The OSGi API based on strings is used in those cases because it allows us to be more lazy by not creating a class loader until the last moment in time. I think the biggest mistake we made in OSGi 12 years ago is not to include the DS concepts in the core ... :-(
您不能使用值
“LogService”
作为获取 ServiceReference 的类名,因为您必须使用完全限定的类名
“org.osgi.services.log.LogService”
。如果你这样导入包:
org.osgi.services.log;分辨率:=可选
并且您使用 ServiceTracker 来跟踪 BundleActivator.start() 方法中的服务我建议使用
"org.osgi.services.log.LogService"
而不是LogService.class.getName() ServiceTracker 初始化。在这种情况下,您将不会在捆绑包启动时收到
NoClassDefFoundError/ClassNotFountException
。You cannot use value
"LogService"
as a class name to get ServiceReference, because you have to use fully qualified class name
"org.osgi.services.log.LogService"
.If you import package this way:
org.osgi.services.log;resolution:=optional
and you use ServiceTracker to track services in BundleActivator.start() method I suggest to use
"org.osgi.services.log.LogService"
instead ofLogService.class.getName()
on ServiceTracker initializazion. In this case you'll not getNoClassDefFoundError/ClassNotFountException
on bundle start.正如 basszero 提到的,您应该考虑使用 ServiceTracker。它相当容易使用,并且还支持更好的编程模式。您绝不能假设您过去某个时间获得的 ServiceReference 仍然有效。 ServiceReference 指向的服务可能已经消失。当服务注册或取消注册时,ServiceTracker 会自动通知您。
As basszero mentioned you should consider to use ServiceTracker. It is fairly easy to use and also supports a much better programming pattern. You must never assume that a ServiceReference you got sometime in the past is still valid. The service the ServiceReference points to might have gone away. The ServiceTracker will automatically notify you when a service is registered or unregistered.