I just stumbled over a phenomenon in my code which comes down to this:
I have an OSGi Declarative Service providing two service interfaces configured as follows:
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" deactivate="dispose" enabled="true" name="redacted.redactedstore">
<implementation class="redacted.RedactedStore"/>
<service>
<provide interface="redacted.IRedactedStore"/>
<provide interface="redacted.IRedactedStoreControl"/>
</service>
</scr:component>
In my code, I have two different threads which both open a ServiceTracker
to get the service instance, but via different interfaces:
tracker = new ServiceTracker<>(getBundle().getBundleContext(), <serviceClass>.class, null);
tracker.open();
tracker.waitForService(1000l);
So one thread uses IRedactedStore
as service class and the other uses IRedactedStoreControl
as service interface.
So what seems to happen is that when both threads run in parallel at the right time, the Equinox SCR will instantiate not one (as I would expect) but two instances of the component implementation class.
Is this behavior correct? Or is this a bug in the Equinox implementation of OSGi?
If the behavior is correct, can I do something in my code to prevent that by configuring the service another way? (of course I could restructure the service so it only provides one interface, or I could synchronize the service trackers...)
OSGi declarative services are the OSGi way to handle the instantiation problem: the fact that we want to code to interfaces, but we need some way to instantiate classes and some way to provide some concrete instance of an interface in order for the parts of our modular application to work together.
The @Component annotation makes the class an OSGi component. Setting a service property to a particular service type in the annotation, allows other components to reference the service component by the specified service type.
That means, if you want to use declarative services in your application, you need to ensure that a Service Component Runtime bundle is installed and activated in your environment. When talking about OSGi declarative services you will always talk about components.
Increasingly Declarative Services (DS) is the backbone of OSGi. While other Dependency Injection (DI) frameworks can be used with OSGi, the OSGi Alliance strongly recommend DS.
Declarative Services (DS) Increasingly Declarative Services (DS) is the backbone of OSGi. While other Dependency Injection (DI) frameworks can be used with OSGi, the OSGi Alliance strongly recommend DS. All of the enRoute examples are DS based and walk you from the simplest of DS components quickstart through a range of DS capabilities.
Note: When using OSGi declarative services, it’s good practice to use the lazy bundle activation policy (Bundle-ActivationPolicy: lazy), which means instantiation of declarative services takes place just before the service is called.
For non prototype scope component I would expect that it is created only once. See declarative services spec.
If this issue only happens when the service trackers run in parallel then I suspect it might be an concurrency issue in equinox scr.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With