Make Java POJOs into OSGi components and services using Java annotations. Features:
- Declarative — no explicit code to publish or consume services
- Lazy — service implementation not loaded until actually requested
- Lifecycle — components have activation/deactivation, bounded by bundle lifecycle
- Configuration — automatically receive config data from Configuration Admin
Two annotation sets exist: OSGi annotations (org.osgi.service.component.annotations) — use these for all new projects. Felix SCR annotations are legacy only.
// Component (not registered as service) — always active by default
@Component
public class MatrixWatcher {
// component logic
}
// Service — registered in service registry, lazy by default
@Component(service = OracleService.class, immediate = true)
public class OracleServiceImpl implements OracleService {
// component logic
}
- OSGi Component (only
@Component) is always active by default - OSGi Service (
@Componentwith service attribute) is lazy by default — started when first requested - Never use
immediate=truefor an OSGi Component - Don't use it for services requested by other OSGi services (they'll start on demand)
- Do use
immediate=truefor services only used by request-bound code (e.g. Sling Models) — otherwise started/stopped per request
@Component
public class SentinelComponent {
@Activate
private void activate(ComponentContext context) {
// handle startup
}
@Deactivate
private void deactivate(ComponentContext context) {
// handle shutdown
}
@Modified
private void modified(Map<String, Object> config) {
// react on config change without restart
}
}
// Lifecycle method arguments (any combination):
// - No arguments
// - ComponentContext
// - BundleContext
// - Map<String,Object>
// - Component property type (annotation class)
@Component(service = GatekeeperService.class)
@Designate(ocd = GatekeeperServiceImpl.Config.class)
public class GatekeeperServiceImpl implements GatekeeperService {
@ObjectClassDefinition(name = "Gatekeeper Configuration")
@interface Config {
@AttributeDefinition(description = "URL of gate service.")
String entryPointUrl();
@AttributeDefinition(description = "Timeout in seconds.")
int timeout() default 5;
}
@Activate
private void activate(Config config) {
String url = config.entryPointUrl();
int timeout = config.timeout();
}
}
// 0..n instances with different configurations each
@Component(service = SentinelService.class)
@Designate(ocd = SentinelServiceImpl.Config.class, factory = true)
public class SentinelServiceImpl implements SentinelService {
@ObjectClassDefinition(name = "Sentinel Service Factory")
@interface Config {
@AttributeDefinition(description = "Sentinel sector name")
String sectorName();
}
@Activate
private void activate(Config config) {
// Each factory instance has its own config
}
}
Additional OSGi component properties (readable by consumers, not part of OSGi config):
@Component(service = OracleService.class,
property = {
"property1=item1",
"property1=item2",
"property2:Integer=12345"
})
// Mandatory single reference (default)
@Reference
private GatekeeperService gatekeeperService;
// Optional single reference
@Reference(cardinality = ReferenceCardinality.OPTIONAL)
private OracleService oracleService;
// Static multiple reference — component restarts if deps change
@Reference(cardinality = ReferenceCardinality.MULTIPLE,
policy = ReferencePolicy.STATIC,
policyOption = ReferencePolicyOption.GREEDY)
private List<SentinelService> sentinels;
// Dynamic multiple reference — services injected/removed at runtime
@Reference(cardinality = ReferenceCardinality.MULTIPLE,
policy = ReferencePolicy.DYNAMIC,
policyOption = ReferencePolicyOption.GREEDY)
private volatile List<SentinelService> dynamicSentinels;
// Always use volatile for dynamic references!
// Filter based on service properties using LDAP-like syntax
@Reference(target = "(sectorName=mainframe)",
cardinality = ReferenceCardinality.MULTIPLE,
policy = ReferencePolicy.DYNAMIC)
private volatile List<SentinelService> mainframeSentinels;
// Filter syntax examples (RFC 1960):
// (cn=Neo)
// (!(cn=Smith))
// (&(objectClass=Agent)(|(sn=Smith)(cn=Agent*)))
// (sector=sector*)
Service scopes:
SINGLETON— single instance in OSGi containerBUNDLE— single instance per using bundlePROTOTYPE— new instance for each reference
Reference scopes:
BUNDLE— single instance for all services in this bundlePROTOTYPE— new instance if service supports it, otherwise sharedPROTOTYPE_REQUIRED— requires PROTOTYPE service scope, fails otherwise