Prioritizing OSGi service selection within a container when more than one implementation exist
I am playing with OSGi and have a few bundles. Bundle A and B both contain a registered service which implements a single interface. The third bundle C includes code to lookup a service implementing the previously mentioned interface. The A and B bundles have different version numbers, however it appears that C picks up the service from the first started bundle. I have changed the start level to do the right thing, but version is only used to accept rather than order which service is returned.
A version 1.0 start level 1
B version 1.1 start level 2
C requires both bundles, start level 3
In the above example C always gets the service from A even though B has a higher bundle version. However, if I switch the start level, so B starts before A, C sees the B service.
I have searched the OSGi website and there is no clear explaination of whether versioning of a bundle is used to prioritise a service over another. My understanding seems to indicate that start level is supposed to be used to order bundle startup so开发者_运维问答 that dependencies can be satisified correctly. However it appears to be overloaded so that it also prioritises service priority. Given all the above, I guess it makes sense not to use the bundle version in selection because the version number is just a number relative to nothing.
What is the best way to prioritise one service over another, besides start level?
The best way of prioritizing OSGi services to use SERVICE_RANKING service property. This property may be supplied in the properties
object passed to the
BundleContext.registerService() method.
According to the documentation of the BundleContext.getServiceReference() method:
If multiple such services exist, the service with the highest ranking (as specified in its Constants.SERVICE_RANKING property) is returned.
If there is a tie in ranking, the service with the lowest service ID (as specified in its Constants.SERVICE_ID property); that is, the service that was registered first is returned.
If the service is registered by a third-party library you may not have control over it's ranking or registered properties. Using ServiceTracker
gives you more control.
For example, you can do something like this :
ServiceTracker tracker = new ServiceTracker (bundleContext, serviceClass ,new ServiceTrackerCustomizer () {
@Override
public Object addingService(ServiceReference srvRef) {
boolean criteria = // whatever your criteria is for prioritizing
if(criteria)
return bundleContext.getService(srvRef);
else
return null;
}
@Override
public void modifiedService(ServiceReference srvRef, Object arg1) {
}
@Override
public void removedService(ServiceReference srvRef, Object arg1) {
}
});
tracker.open();
Object service = tracker.getService();
In org.osgi.framework.BundleContext.registerService(String[], Object, Dictionary)
you can specify arbitrary properties in the Dictionary
. To find a service, you can specify a filter in org.osgi.framework.BundleContext.getServiceReferences(String, String)
. And if that's not enough, you can check org.osgi.framework.ServiceReference.getProperty(String)
, for example for a priority value.
精彩评论