Skip to main content

Command Palette

Search for a command to run...

Multiple Implementations of the Same Service in OSGi

Updated
3 min read

One of the most common questions when working with OSGi services is:

What if more than one bundle provides an implementation of the same service interface?

In traditional Java or even Spring-based applications, this often leads to ambiguity errors or requires manual configuration.
In OSGi, however, multiple implementations are not an edge case - they are a core feature.

Let’s break down how OSGi handles this cleanly and dynamically.


The Scenario

Assume we have a common service interface:

public interface PaymentService {
    void pay();
}

Now imagine multiple bundles provide implementations:

@Component(service = PaymentService.class)
public class PaypalPaymentService implements PaymentService {
    public void pay() {
        System.out.println("PayPal payment");
    }
}
@Component(service = PaymentService.class)
public class CardPaymentService implements PaymentService {
    public void pay() {
        System.out.println("Card payment");
    }
}

Both services are:

  • Registered in the Service Registry

  • Available at the same time

  • Dynamically manageable

So… which one gets injected?


1. Default Behavior: One Is Chosen (Non-deterministic)

If you write:

@Reference
private PaymentService paymentService;

OSGi will:

  • Pick one matching service

  • Selection is not guaranteed unless you guide it

This is usually not recommended


2. Service Ranking: Prefer One Implementation

OSGi allows services to declare a ranking:

@Component(
    service = PaymentService.class,
    property = "service.ranking=100"
)
public class PaypalPaymentService implements PaymentService {}
@Component(
    service = PaymentService.class,
    property = "service.ranking=10"
)
public class CardPaymentService implements PaymentService {}

- Higher service.ranking wins
- DS automatically injects the highest-ranked service

This is useful when:

  • You have a default implementation

  • Others act as fallbacks


3. Filter-Based Injection: Select Explicitly

You can select a service using properties:

@Component(
    service = PaymentService.class,
    property = "type=paypal"
)
public class PaypalPaymentService {}
@Component(
    service = PaymentService.class,
    property = "type=card"
)
public class CardPaymentService {}
@Reference(target = "(type=paypal)")
private PaymentService paymentService;

This gives precise control over which service is injected.


4. Inject All Implementations (Preferred for Extensibility)

OSGi allows multiple services to be injected at once:

@Reference(
    cardinality = ReferenceCardinality.MULTIPLE,
    policy = ReferencePolicy.DYNAMIC
)
private List<PaymentService> paymentServices;

This is powerful because:

  • Services can be added or removed at runtime

  • The list updates automatically

  • No restart required

Perfect for:

  • Plugin systems

  • Strategy patterns

  • Dynamic extensions


5. Optional References

If a service is optional:

@Reference(
    cardinality = ReferenceCardinality.OPTIONAL,
    policy = ReferencePolicy.DYNAMIC
)
private PaymentService paymentService;

The component:

  • Activates even if no service is present

  • Gets updated when one appears later

OSGi Deep Dive Series

Part 6 of 10

OSGi is often described as complex or hard to understand, mainly because its concepts are deeply interconnected - containers, bundles, classloading, services, IoC, DI, and declarative components all work together at runtime.

Up next

OSGi Deep Dive Series: Complete Guide to Modular Java

This post serves as a central index for my complete OSGi Deep Dive series. OSGi is often described as complex or hard to understand, mainly because its concepts are deeply interconnected — containers,