OSGi (Open Service Gateway Initiative) provides a powerful Java framework for building modular, dynamic, and maintainable applications. Modern platforms like Adobe Experience Manager (AEM) leverage OSGi extensively—via the Apache Felix implementation—to create a flexible, service-oriented architecture. In this environment, developers can install, update, and remove modules at runtime without restarting the system. This article breaks down OSGi fundamentals—including bundles, components, and services—and uses practical examples to explain how they interact.
What Is OSGi?
OSGi provides both a modular system and a service platform for Java. It consists of two major parts:
1. Bundle Specification (Modularization Layer)
OSGi applications are packaged as bundles—specialized JAR files containing additional metadata (MANIFEST.MF) that describes:
- Package imports and exports
- Versioning
- Dependencies
- Lifecycle instructions
A bundle can be:
- Installed
- Started
- Stopped
- Updated
- Uninstalled
All at runtime, without restarting the JVM.
Examples of OSGi modularity:
- Adobe Experience Manager (AEM) uses Apache Felix (an OSGi implementation)
- Eclipse IDE is built entirely on OSGi bundles
2. JVM-Level Service Registry
OSGi provides a dynamic Service Registry, enabling bundles to:
- Publish services
- Discover available services
- Bind to and use services at runtime
This creates a service-oriented architecture (SOA) within the JVM itself.
Understanding Bundles
A bundle is the smallest unit of modularization in OSGi. It is simply a JAR file enhanced with OSGi-specific metadata. Typical bundle roles include:
- Business logic modules
- Utility libraries
- API interfaces
- Implementations of services
Bundles cooperate through well-defined contracts, reducing coupling and increasing system maintainability.
OSGi Components
A component is the fundamental building block inside an OSGi bundle. Its lifecycle is managed by an OSGi component framework such as:
- Declarative Services (DS) — most common in AEM
- Blueprint
- iPOJO
Key characteristics of an OSGi Component
- It is a Java object managed by the OSGi container
- Defined using @Component annotation
- Can be started, stopped, activated, deactivated by the container
- May publish itself as a service
- May consume (bind to) other services via @Reference
Active vs Passive Components
- Active component → Has lifecycle callbacks like activate() and deactivate()
- Passive component → Requires no lifecycle callbacks
Example: Basic OSGi Component
@Component(service = MyComponent.class)
public class MyComponent {
@Activate
protected void activate() {
System.out.println("Component Activated");
}
@Deactivate
protected void deactivate() {
System.out.println("Component Deactivated");
}
}
OSGi Services
While all services function as components, not all components act as services. A service simply represents a component that exposes its functionality to other bundles through the Service Registry.
Defining a Service
To designate a component as a service, expose it using the service attribute:
public interface GreetingService {
String greet(String name);
}
@Component(service = GreetingService.class)
public class GreetingServiceImpl implements GreetingService {
public String greet(String name) {
return "Hello, " + name;
}
}
Consuming a Service
Other components can depend on this service via @Reference:
@Component(service = GreetingClient.class)
public class GreetingClient {
@Reference
private GreetingService greetingService;
public void execute() {
System.out.println(greetingService.greet("StacKnowledge"));
}
}
What makes OSGi services powerful?
- Dynamic service discovery
- Automatic binding/unbinding as services appear/disappear
- Loose coupling between modules
- Singleton service instances at runtime
OSGi Component vs OSGi Service: Key Differences
| Feature | OSGi Component | OSGi Service |
| Managed by OSGi container | ✔ Yes | ✔ Yes |
| Can expose functionality | Optional | Mandatory |
| Can consume services | ✔ Yes | ✔ Yes |
| Can be injected via @Reference | ❌ No | ✔ Yes |
| Shareable across bundles | Limited | ✔ Yes |
| Must specify service attribute | No | Yes |
Summary
- All services are components, but not all components are services
- Components cannot be injected into other components; only services can be injected
- Services enable cross-bundle communication
Real-World Example in AEM
In AEM:
- Sling Models and servlets are components
- Backend business logic (e.g., workflow handlers, schedulers, utilities) is typically implemented as OSGi services
- Other components consume these services through @Reference
This ensures modular, testable, and maintainable code.
Conclusion
OSGi provides a robust modular architecture that enables the dynamic loading, execution, and management of application components and services. To build clean, scalable, and maintainable applications—especially on OSGi-centric platforms like AEM—developers must understand the fundamental differences between components, services, and bundles.
Mastering these concepts enables developers to:
- Build reusable modules
- Support runtime flexibility
- Reduce coupling between code
- Leverage the full power of the OSGi container