# Service Locator The **Service Locator** is a design pattern in which a class obtains its dependencies by *asking* a central registry for them, rather than having them passed in. Instead of `constructor(db: Database)`, the class does `this.db = ServiceLocator.get<Database>()`. The locator holds a map of service-type → instance and hands them out on request. It's one way to implement [[Inversion of Control (IoC)]] — the locator owns construction and lifetime — and one way to satisfy the [[Dependency Inversion Principle (DIP)]] when the locator returns abstractions. But it's widely considered an *antipattern* in modern code, especially compared to [[Dependency Injection (DI)]]. ## Mechanism A `ServiceLocator` is a global (or near-global) registry. At application startup, services are registered: `ServiceLocator.register(Database, new PostgresClient(...))`. Anywhere in the codebase, code can call `ServiceLocator.get(Database)` and receive the instance. The locator may be a static class, a singleton, or a thread-local context. ``` Class A ──asks──> ServiceLocator ──hands back──> Database instance ``` Compare with constructor DI: ``` Composition Root ──constructs and passes──> Class A(database) ``` Same goal — A doesn't `new` its own database — but radically different visibility properties. ## Why it's tempting - **No wiring at the call site**: any class anywhere can grab any service without plumbing dependencies through constructors. - **Refactoring-light**: adding a new dependency to a deep class doesn't require updating every caller. - **Familiar in some ecosystems**: legacy J2EE (`InitialContext` JNDI lookups), older Spring code, classic ASP.NET (`HttpContext.Current`), Unity game engine. ## Why it's a problem - **Hidden dependencies**: a class's *true* dependencies aren't visible from its constructor or signature. Reading a class no longer tells you what it needs to function. [[Mark Seemann]] calls Service Locator an antipattern primarily for this reason. - **Hostile to testing**: tests must configure the global locator before exercising the class, then tear it down. Parallel tests fight over shared state. Mocks bleed across test boundaries. - **Runtime failures instead of compile-time**: missing registrations explode at first use, not at startup. Some locators don't even fail loudly — they return `null`. - **Coupling to the locator itself**: every class that uses the pattern depends on the locator class, not just on its actual collaborators. - **Encourages God-objects**: it's frictionless to add "just one more" dependency, so classes grow until they pull in half the system. ## When it might be acceptable - **Framework boundary code** where the framework constructs your object and you genuinely cannot influence its constructor (e.g., legacy Servlet API, some plugin SPIs). - **Plugin / extension discovery** where the set of services is dynamic and unknown at compile time. - **Lightweight scripts** where the test/lifecycle costs are negligible. In all other cases, prefer constructor [[Dependency Injection (DI)]] from a [[Composition Root]]. ## Service Locator vs DI | | Service Locator | Dependency Injection | |---|---|---| | **Direction** | Class *pulls* its dependencies | Dependencies *pushed* into the class | | **Visibility** | Hidden inside method bodies | Explicit in constructor / setter | | **Test setup** | Configure global registry | Pass test doubles directly | | **Failure mode** | Runtime, on first use | Compile-time or composition-root startup | | **Coupling** | Class → Locator → Service | Class → Service abstraction only | ## References - Martin Fowler — *Inversion of Control Containers and the Dependency Injection pattern* (2004) — https://martinfowler.com/articles/injection.html (compares Service Locator and DI explicitly) - Mark Seemann — *Service Locator is an Anti-Pattern* (2010) — https://blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Pattern/ ## Related - [[Dependency Injection (DI)]] - [[Inversion of Control (IoC)]] - [[Dependency Inversion Principle (DIP)]] - [[Composition Root]] - [[Loose Coupling]] - [[SOLID Principles]] - [[Mark Seemann]] - [[Martin Fowler]]