这一节对比一下BundleContext上几个getServiceReference方法的差别:
1、getAllServiceReferences(String clazz, String filter)方法:
这个方法从服务注册表中检索所有以指定服务名称注册的服务,并且按照服务过滤条件进行过滤。
这里需要注意2点:一是服务注册时,可选提供一些服务属性,那么在服务检索时,可以根据
服务属性进行过滤。其中,服务注册时对应的ClassName,也被作为一条属性存储:
即:Constants.OBJECTCLASS = {className} ,所以:
getServiceReference("demo.Foo", null) 等价于 getServiceReference(null, "(objectClass=demo.Foo)")
二是不同构件、或者同一个构件可以使用相同的className来注册多个服务,对于某一个服务客户端来说,
服务客户端对其中的部分服务可能是不可见的。这儿的“不可见”取决于ClassLoader的委托关系。
这是构件从Installed状态变成Resolved状态时就已经确定的。
注意,对于getAllServiceReferences方法,是不做可见性过滤的。如果你明确服务是单一的,不会存在可见性问题,就可以忽略这种可见性问题。
当然,这儿的不可见是指影响赋值时的强制类型转换(会报Class cast之类的错误),但不影响反射方式使用对象。
2、getServiceReferences(Class<S> clazz, String filter)方法:
和上一个方法的唯一区别就是在上一个方法的调用结果上, 再添加一层可见性检查。
可见性检查通过调用:ServiceReference.isAssignableTo(Bundle bundle, String className)方法实现。
3、getServiceReferences(String clazz, String filter)方法:
和上一个方法想同,唯一的差别是,一个返回数组、一个返回集合。(有点冗余的方法)
4、getServiceReference(Class<S> clazz)方法:
在getServiceReferences方法的基础上,挑选一个最佳服务返回;
那么最佳服务如何选择呢?请看ServiceReference.compareTo方法的说明:
即:在服务注册时,可以提供一个SERVICE_RANKING( "service.ranking")属性,用来指明服务优先级,
如果未指定的话,缺省优先级为 0
如果两个服务优先级相同(比如,都没有指定,都是0),那么它们的优先级取决于SERVICE_ID(即service.id),
这是在注册服务时,由框架自动生成的,取决于服务注册的先后次序。
5、getServiceReference(String clazz)方法:
和上一个方法相同,只是参数形式差异而已。
6、说完了getServiceReferences、和getAllServiceReferences的区别,
同样的,这样的差别在ServiceTracker中也有,差别反映在ServiceTracker的两个open方法上:
看下面代码就明白了:
public void open() {
open(false);
}
public void open(boolean trackAllServices) {}
缺省的open方法并非跟踪所有服务,也就意味着对服务的可见性进行过滤;
等价于open(false)的效果。
显式调用open(true)即可对省去服务可见性过滤操作,如果服务数量庞大,服务可见性过滤会消耗较多时间,对性能产生一定的影响。
7、再扯一下和服务相关的两个看上去容易混淆的单词:
String SERVICE_ID = "service.id";
String SERVICE_PID = "service.pid";
其中,service.id是由框架在运行时动态产生的一个唯一的序列号;
作用之一就是上面的寻找最佳匹配服务之时;
而service.pid是一个由服务提供者注册服务时自己设定的属性。它用来标识一个持久化的、可在多次JVM启动期间
都可以唯一匹配到的标识。
作用之一是用于OSGi的配置管理服务。框架在启动时从持久化存储中拿到一份配置信息时,可以知道它属于哪个服务所有。
从而可以通知该服务对象更新配置。