OSGi services & Declarative Services
Purpose: Write, wire and configure backend services with DS annotations — the dependency injection layer of AEM.
Who this page is for
| Audience | Why it matters to you |
|---|---|
| Backend engineers | Core mechanics of every backend feature |
Service in 20 lines
public interface PremiumCalculator { double monthly(String planId); }
@Component(service = PremiumCalculator.class)
@Designate(ocd = PremiumCalculatorImpl.Config.class)
public class PremiumCalculatorImpl implements PremiumCalculator {
@ObjectClassDefinition(name = "PHI Premium Calculator")
@interface Config {
@AttributeDefinition(name = "Loading factor")
double loadingFactor() default 1.0;
}
private double loadingFactor;
@Activate @Modified
void activate(Config cfg) { this.loadingFactor = cfg.loadingFactor(); }
@Override public double monthly(String planId) { /* … */ return 0; }
}
Consume it anywhere: @Reference private PremiumCalculator calculator; (services) or @OSGiService (Sling Models).
Lifecycle & wiring
| Annotation | Meaning |
|---|---|
| @Component | Register as DS component (service if service= given) |
| @Activate / @Deactivate / @Modified | Lifecycle callbacks; @Modified = config changed without restart |
| @Reference | Inject another service; policy/cardinality control optionality |
| @Designate + OCD | Typed, console-visible configuration |
Config values come from ui.config files named by PID (com.academy.phi.core.PremiumCalculatorImpl.cfg.json), per run mode. Live values visible in /system/console/configMgr.
Design rules
- Program to interfaces; register the interface, not the impl class.
- Services are singletons by default — stateless or thread-safe only.
- Optional references (
cardinality = OPTIONAL) for integrations that may be absent per environment. - Don't hold ResourceResolvers/sessions as fields — obtain per operation via factory, close promptly.
- Component not showing up? /system/console/components shows unsatisfied references — see Bundle won't start.