Service scope vs Component scope?

This is not really related to Bnd (sorry!), but…

I have naively been assuming that declaring a component as @Component(scope = SINGLETON) would mean its services would be registered with property service.scope=singleton too. And yet I am now discovering that they are being registered with service.scope=bundle instead?! :confused:

The documentation implies that service.scope=bundle means that BundleContext.registerService() was passed an instance of ServiceFactory for its service parameter, and I suppose that wouldn’t preclude that service still being a singleton in practice, but…

I was hoping to use a filter (service.scope=singleton) to select only SINGLETON components from a pool of both SINGLETON and PROTOTYPE components. I can obviously change this filter to (!(service.scope=prototype)) instead, but now I am wondering if that would work either because “service scope” and “component scope” are clearly not quite the same thing.

Have I made a huge and terrible error here please? Do OSGi Declarative Services not distinguish between service and bundle scopes? After all, it isn’t as if there’s a component.scope property registered along with component.name and component.id. Although support for references with ReferenceScope.PROTOTYPE_REQUIRED must obviously be implemented somehow too, and a filter like mine would seem to be a reasonable candidate for that.

Thanks for any advice here,
Cheers,
Chris

Your component services having @Component(scope = SINGLETON) are singletons :slight_smile: (You should be able to write tests that prove this pretty easily.)

The property service.scope is not one that is set by a service provider. In fact if you set it, it will be overruled based on the type of object registered.

Table 5.1 Standard Service Properties describes service.scope as:

The service.scope property identifies the service’s scope. The Framework must set this property automatically. If the registered service object implements PrototypeServiceFactory, then the value will be prototype. Otherwise, if the registered service object implements ServiceFactory, then the value will be bundle. Otherwise, the value will be singleton. See Service Scope.

DS always registers it’s services using either ServiceFactory or PrototypeServiceFactory. It does this so that it can control the lifecycle of the actual service “objects” that it will ultimately provide.

So what you’re witnessing is a quirk of how DS is implemented.

This is what enables DS components to be delayed based on the state of references or configuration dependencies or to be externally “disabled”. So the service.scope=bundle while true reflection of the fact that the service was actually registered as a ServiceFactory does not reflect the reality that DS (and not the service registry) is providing a singleton object whenever ServiceFactory.getService is called.

I hope that helps explain what you’re seeing :slight_smile:

Now, as you’ve observed, there’s no property on the resulting service reference that outwardly lets you determine between a “component” that is singleton vs. bundle scope. For prototype scope the service.scope should be accurate. It’s those other two which are next to impossible to outwardly distinguish between which is unfortunate.

You can query SCR, which allows you to e.g. display the information like this:

image

(Taken from here.)

Thanks, I suspected the explanation was something like that. Not having a programmatic way to select singleton components is indeed unfortunate, but the blocker in my case would have been not being able to exclude prototype components.

Cheers,
Chris