Skip to main content

Command Palette

Search for a command to run...

Inversion of Control (IoC) and Dependency Injection (DI) in OSGi

Updated
5 min read

In the previous post, we explored bundle lifecycle, bundle activators, and the Service Registry. Now that we understand how services are registered and made available, it’s time to explore how bundles actually consume these services in a flexible and loosely coupled way.

This is where Inversion of Control (IoC) and Dependency Injection (DI) come into the picture. Instead of bundles creating or looking up their dependencies manually, the container takes control and injects the required services automatically.

In this post, we’ll cover:

  • What IoC means in OSGi and how the Service Registry enables it

  • How DI works, including dynamic injection of services at runtime


Inversion of Control (IoC) in OSGi

What is IoC?

Inversion of Control is a design principle where the framework or container controls the creation and management of objects instead of the application code itself.

In other words:

  • Instead of your code calling dependencies,

  • The container decides what dependencies to provide, when to provide them, and how to wire them together.

IoC is the foundation of loose coupling and modularity. Without it, your code would have tight dependencies and would break when anything changes.

IoC vs Traditional Java

In a traditional Java application:

// Object created in code
PaymentService paymentService = new PaymentServiceImpl();
...
paymentService.processOrder();

With IoC

// Injected dynamically by the OSGi container
@Reference
private PaymentService paymentService;
...
paymentService.processOrder();

How OSGi Implements IoC

In OSGi, the Service Registry is the IoC mechanism:

  1. Bundles register services with the registry.

  2. Bundles declare dependencies on interfaces (not implementations).

  3. The OSGi container injects the service dynamically.

  4. If the service disappears or is updated, the container can rebind it automatically.

This inverts control from bundle → service to container → bundle → service.


Benefits of IoC in OSGi

  1. Loose Coupling: Bundles depend only on interfaces, not concrete implementations.

  2. Dynamic Wiring: Services can appear, disappear, or be replaced at runtime.

  3. Hot Deployment: Bundles and services can be updated without restarting the JVM.

  4. Multiple Implementations: Multiple versions or implementations of the same interface can coexist.

  5. Simplified Testing: Bundles can be tested independently with mock services.


Key Takeaways

  • IoC is about who controls object creation and wiring.

  • In OSGi, the container is in charge, not the bundles.

  • The Service Registry is the central mechanism enabling IoC.

  • Understanding IoC is critical before learning DI, Declarative Services, and component-based development.


Dependency Injection (DI) in OSGi

In the last section, we discussed Inversion of Control (IoC) how the OSGi container takes control of when and how bundles get their dependencies.

Dependency Injection (DI) is the practical implementation of IoC: it’s the mechanism by which the container actually provides the required service objects to your bundles.

What is Dependency Injection?

At its core, DI means:

A component does not create its dependencies. Instead, they are injected by the container, either automatically or via configuration.

DI is the how behind IoC — IoC is the principle, DI is the implementation.

Forms of DI in OSGi

  1. Programmatic DI – the bundle manually queries the Service Registry to get dependencies.

  2. Declarative DI – the container injects services automatically based on metadata or annotations.

Programmatic DI (Manual Injection)

Here, the bundle retrieves services manually from the Service Registry.

ServiceReference<PaymentService> ref = context.getServiceReference(PaymentService.class);
PaymentService paymentService = context.getService(ref);

OrderProcessor processor = new OrderProcessor(paymentService);
processor.process(order);

Characteristics:

  • The bundle still has some control over dependency retrieval.

  • Dependencies are retrieved at runtime but manually.

  • Harder to manage dynamic updates or multiple implementations.

Declarative DI (Automatic Injection)

Declarative Services (DS) and annotations like @Reference let the container inject services automatically.

@Component
public class OrderProcessor {

    @Reference
    private PaymentService paymentService;

    public void process(Order order) {
        paymentService.processPayment(order);
    }
}

How it works:

  • The container reads metadata (from the bundle manifest or annotations).

  • It finds an implementation registered in the Service Registry.

  • It injects the dependency automatically.

  • If the service disappears, the container can rebind a new implementation dynamically.

Advantages over programmatic DI:

  • No boilerplate code for service lookup.

  • Automatic handling of service lifecycle and updates.

  • Enables hot-swapping of services at runtime.


How DI Relates to IoC

  • IoC: Shifts control of dependency management to the container.

  • DI: Mechanism for providing those dependencies to bundles.

  • Together, they enable:

  1. Loose coupling

  2. Dynamic wiring at runtime

  3. Hot deployment and updates without JVM restart

The bundle never creates or manages its services - that’s the magic of OSGi.


Key Takeaways

  • DI is the practical side of IoC - the container injects services rather than the bundle creating them.

  • OSGi DI can be dynamic at runtime, unlike traditional static DI frameworks.

  • Declarative Services (DS) leverage DI to automatically bind services and respond to lifecycle changes.

  • Understanding DI is essential before we dive into Components, Services, and SCR in the next post.


Wrapping Up

In this post, we explored Inversion of Control (IoC) and Dependency Injection (DI) in OSGi:

  • IoC shifts control of dependencies from your code to the OSGi container.

  • DI is the mechanism the container uses to provide services to your bundles.

  • OSGi’s declarative DI allows services to be injected automatically and dynamically, enabling hot-swapping, multiple versions, and zero-downtime updates.

  • Understanding the Service Registry is key, as it’s the foundation that makes IoC and DI possible in OSGi.

Knowing IoC and DI is crucial before diving into Components and Services, as they rely on these principles for dynamic service injection and runtime flexibility.


What’s Next?

In the next post, we’ll dive into:

  • Components and Services: How OSGi bundles expose and consume services.

  • Declarative Services and SCR: Simplifying service management with annotations and metadata.

OSGi Deep Dive Series

Part 4 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

A Deep Dive into OSGi Components and Services

The Final Post in Our OSGi Series! In our previous post, we explored the IoC, and Dependency Injection (DI) - the foundation that makes OSGi modular, dynamic, and flexible. Understanding these concept