What's the difference between the Dependency Injection and Service Locator patterns?

Design PatternsDependency InjectionService Locator

Design Patterns Problem Overview


Both patterns seem like an implementation of the principle of inversion of control. That is, that an object should not know how to construct its dependencies.

Dependency Injection (DI) seems to use a constructor or setter to "inject" it's dependencies.

Example of using Constructor Injection:

//Foo Needs an IBar
public class Foo
{
  private IBar bar;

  public Foo(IBar bar)
  {
    this.bar = bar;
  }

  //...
}

Service Locator seems to use a "container", which wires up its dependencies and gives foo it's bar.

Example of using a Service Locator:

//Foo Needs an IBar
public class Foo
{
  private IBar bar;

  public Foo()
  {
    this.bar = Container.Get<IBar>();
  }

  //...
}

Because our dependencies are just objects themselves, these dependencies have dependencies, which have even more dependencies, and so on and so forth. Thus, the Inversion of Control Container (or DI Container) was born. Examples: Castle Windsor, Ninject, Structure Map, Spring, etc.)

But a IOC/DI Container looks exactly like a Service Locator. Is calling it a DI Container a bad name? Is an IOC/DI Container just another type of Service Locator? Is the nuance in the fact that we use DI Containers mostly when we have many Dependencies?

Design Patterns Solutions


Solution 1 - Design Patterns

The difference may seem slight, but even with the ServiceLocator, the class is still responsible for creating its dependencies. It just uses the service locator to do it. With DI, the class is given its dependencies. It neither knows, nor cares where they come from. One important result of this is that the DI example is much easier to unit test -- because you can pass it mock implementations of its dependent objects. You could combine the two -- and inject the service locator (or a factory), if you wanted.

Solution 2 - Design Patterns

When you use a service locator, every class will have a dependency on your service locator. This is not the case with dependency injection. The dependency injector will typically be called only once at startup to inject dependencies into some main class. The classes this main class depends on will recursively have their dependencies injected, until you have a complete object graph.

A good comparison: http://martinfowler.com/articles/injection.html

If your dependency injector looks like a service locator, where the classes call the injector directly, it is probably not a dependency injector, but rather a service locator.

Solution 3 - Design Patterns

Service locators hide dependencies - you can't tell by looking at an object whether it hits a database or not (for example) when it obtains connections from a locator. With dependency injection (at least constructor injection) the dependencies are explicit.

Moreover, service locators break encapsulation because they provide a global point of access to dependencies of other objects. With service locator, as with any singleton:

> it becomes difficult to specify the pre and post > conditions for the client object's > interface, because the workings of its > implementation can be meddled with > from outside.

With dependency injection, once an object's dependencies are specified, they are under control of the object itself.

Solution 4 - Design Patterns

Martin Fowler states:

> With service locator the application class asks for it explicitly by a > message to the locator. With injection there is no explicit request, > the service appears in the application class – hence the inversion of > control.

In short: Service Locator and Dependency Injection are just implementations of Dependency Inversion Principle.

The important principle is “Depend upon Abstractions, not upon Concretions”. This will make your software design “loosely coupled”, “extensible”, “flexible”.

You can use the one that best fits your needs. For a big application, having a huge codebase, you'd better use a Service Locator, because Dependency Injection would require more changes to your codebase.

You can check this post: Dependency Inversion: Service Locator or Dependency Injection

Also the classic: Inversion of Control Containers and the Dependency Injection pattern by Martin Fowler

Designing Reusable Classes by Ralph E. Johnson & Brian Foote

However, the one that opened my eyes was: ASP.NET MVC: Resolve or Inject? That’s the Issue… by Dino Esposito

Solution 5 - Design Patterns

A class using constructor DI indicates to consuming code that there are dependencies to be satisfied. If the class uses the SL internally to retrieve such dependencies, the consuming code is not aware of the dependencies. This may on the surface seem better, but it is actually helpful to know of any explicit dependencies. It is better from an architectural view. And when doing testing, you have to know whether a class needs certain dependencies, and configure the SL to provide appropriate fake versions of those dependencies. With DI, just pass in the fakes. Not a huge difference, but it is there.

DI and SL can work together, though. It is useful to have a central location for common dependencies (e.g. settings, logger, etc). Given a class using such deps, you can create a "real" constructor that receives the deps, and a default (no parameter) constructor that retrieves from the SL and forwards to the "real" constructor.

EDIT: and, of course, when you use the SL, you are introducing some coupling to that component. Which is ironic, since the idea of such functionality is to encourage abstractions and reduce coupling. The concerns can be balanced, and it depends on how many places you would need to use the SL. If done as suggested above, just in the default class constructor.

Solution 6 - Design Patterns

Both of them are implementation techniques of IoC. There are also other patterns which implements Inversion of Control:

  • Factory pattern
  • Service locator
  • DI (IoC) Container
  • Dependency injection (constructor injection, parameter injection (if not required), setter injection of interface injection) ...

Service locator and DI Container seem more similar, both of them use a container to define dependencies, which maps abstraction to the concrete implementation.

The main difference is how the dependencies are located, in Service Locator, client code request the dependencies, in DI Container we use a container to create all of objects and it injects dependency as constructor parameters (or properties).

Solution 7 - Design Patterns

In my last project I use both. I use dependency injection for unit testability. I use service locator to hide implementation and being dependent to my IoC container. And YES! Once you use an IoC container (Unity, Ninject, Windsor Castle), you depend on it. And once it is outdated or for some reason you will want to swap it, you will/may need to change your implementation - at least the composition root. But service locator abstracts that phase.

How would you not depend on your IoC container? Either you will need to wrap it on your own (which is a bad idea), or you use a Service Locator to configure your IoC container. So you will tell the Service Locator to get the interface you need, and it will call the IoC container which is configured to retrieve that interface.

In my case, I use ServiceLocator, which is a framework component. And I use Unity for my IoC container. If in the future I need to swap my IoC container with Ninject, all I need to do is to configure my Service Locator to use Ninject instead of Unity. Easy migration.

Here is a great article that explains this scenario; http://www.johandekoning.nl/index.php/2013/03/03/dont-wrap-your-ioc-container/

Solution 8 - Design Patterns

One reason to add, inspired by a documentation update we wrote for the MEF project last week (I help build MEF).

Once an app is made up of potentially thousands of components, it can be difficult to determine whether any particular component can be instantiated correctly. By "instantiated correctly", I mean that in this example based on the Foo component, an instance of IBar and will be available, and that the component providing it will:

  • have its required dependencies,
  • not be involved in any invalid dependency cycles, and
  • in the case of MEF, be supplied with only one instance.

In the second example you gave, where the constructor goes to the IoC container to retrieve its dependencies, the only way that you can test that an instance of Foo will be able to be instantiated correctly with the actual runtime configuration of your app is to actually construct it.

This has all sorts of awkward side-effects at test time, because code that will work at runtime won't necessarily work under a test harness. Mocks won't do, because the real configuration is the thing we need to test, not some test-time setup.

The root of this problem is the difference already called out by @Jon: injecting dependencies through the constructor is declarative, while the second version uses the imperative Service Locator pattern.

An IoC container, when used carefully, can statically analyze the runtime configuration of your app without actually creating any instances of the components involved. Many popular containers provide some variation of this; Microsoft.Composition, which is the version of MEF targeting .NET 4.5 web and Metro style apps, provides a CompositionAssert sample in the wiki documentation. Using it, you can write code like:

 // Whatever you use at runtime to configure the container
var container = CreateContainer();

CompositionAssert.CanExportSingle<Foo>(container);

(See this example).

By verifying the Composition Roots of your application at test time you can potentially catch some errors that may otherwise slip through testing later in the process.

Hope this is an interesting addition to this otherwise comprehensive set of answers on the topic!

Solution 9 - Design Patterns

I think the two work together.

Dependency injection means you push in some dependant class/interface to a consuming class (usually to it's constructor). This decouples the two classes via an interface and means the consuming class can work with many types of "injected dependency" implementations.

The role of the service locator is to pull together your implementation. You setup a service locator via some boot strapping at the start of your program. Bootstrapping is the process of associating a type of implementation to a particular abstract/interface. Which gets created for you at run time. (based on you config or bootstrap). If you hadn't implemented dependency injection, it would be very difficult to utilise a service locator or IOC container.

Solution 10 - Design Patterns

Note: I'm not exactly answering the question. But I feel that this can be useful for new learners of the Dependency Injection pattern who are confused about it with the Service Locator (anti-)pattern who happen to stumble onto this page.

I know the difference between the Service Locator (it's seems to be regarded as an anti-pattern now) and Dependency Injection patterns and can understand concrete examples each pattern, yet I was confused by examples showing a service locator inside the constructor (assume we're doing constructor injection).

"Service Locator" is often used both as the name of a pattern, and as the name to refer to the object (assume too) used in that pattern to obtain objects without using the new operator. Now, that same type of object can also be used at the composition root to perform dependency injection, and that's where the confusion comes in.

The point to note is that you may be using a service locator object inside a DI constructor, but you are not using the "Service Locator pattern". It is less confusing if one refers it as an IoC container object instead, as you may have guessed that they essentially do the same thing (do correct me if I'm wrong).

Whether it is referred to as a service locator (or just locator), or as an IoC container (or just container) makes no difference as you have guessed, they are probably referring to the same abstraction (do correct me if I'm wrong). It's just that calling it a service locator suggests that one is using the Service Locator anti-pattern together with the Dependency Injection pattern.

IMHO, naming it a 'locator' instead of 'location' or 'locating', can also cause one to sometimes think that the service locator in an article is referring to the Service Locator container, and not the Service Locator (anti-)pattern, especially when there's a related pattern called Dependency Injection and not Dependency Injector.

Solution 11 - Design Patterns

Following simple conception gave me a clearer understanding of difference between Service Locator and DI Container:

  • Service Locator is used in the consumer and it pulls services by ID from some storage by direct consumer's request

  • DI Container is located somewhere outside and it takes services from some storage and pushes them to the consumer (no matter via constructor or via method)

However, we can talk about difference between these only in context of concrete consumer usage. When Service Locator and DI Container are used in composition root, they are almost similar.

Solution 12 - Design Patterns

In this oversimplified case there is no difference and they can be used interchangeably. However, real world problems are not as simple. Just assume that the Bar class itself had another dependency named D. In that case your service locator wouldn't be able to resolve that dependency and you would have to instantiate it within the D class; because it is the responsibility of your classes to instantiate their dependencies. It would even get worse if the D class itself had other dependencies and in real-world situations it usually gets even more complicated than that. In such scenarios DI is a better solution than ServiceLocator.

Solution 13 - Design Patterns

Service Locator and Dependency Injection are both Object Access Pattern implementation that obey the Dependency Inversion Principle


Dependency Injection are [static/global] object access pattern

Service Locator are [dynamic] object access pattern


If you need to handle [dynamic structure] like [ui tree] or any [fractal designed application], you may need Service Locator.

Example:

  • createContext/useContext of React
  • provide/inject of Vue
  • Providers of angular

If you only want to get a instance from your class that don't care about the hierarchy of the application and the position of the instance in that hierarchy, you should use DI.

Example:

  • Annotation in C#/Java

Service Locator is used when you don't know the actual provider of the service before runtime.

DI is used when you know it's the static container that provides that service.


Service Locator pattern is more like a module level Dependency Providers, while DI is global level.

It's very useful when there is a sub-module that declare dependency of a service that should be provided by it's parent-module instead of a static resolve type(singleton/transient/static-scoped).

It can be implemented by a scoped injection pattern of DI while the scope is defined by the module structure/relation of the application.


Personal suggestion:

  1. use DI wherever possible.
  2. use Service Locator if you have to deal with dynamic/runtime service resolvation in fractal structure.
  3. encapsulate the Service Locator as a scoped DI, for example: @inject({ scope: 'contextual' })
  4. Locate the service by interface, instead of the class/constructor.

Detailed information: https://docs.microsoft.com/zh-cn/dotnet/core/extensions/dependency-injection-guidelines#recommendations

Solution 14 - Design Patterns

What’s the difference (if any) between Dependency Injection and Service Locator? Both patterns are good at implementing the Dependency Inversion principle. The Service Locator pattern is easier to use in an existing codebase as it makes the overall design looser without forcing changes to the public interface. For this same reason, code that is based on the Service Locator pattern is less readable than equivalent code that is based on Dependency Injection.

The Dependency Injection pattern makes it clear since the signature which dependencies a class (or a method) is going to have. For this reason, the resulting code is cleaner and more readable.

Solution 15 - Design Patterns

DI container is a superset of service locator. It can be used to locate a service, with additional capability of assembling (wiring) the injections of dependency.

Solution 16 - Design Patterns

For the record

//Foo Needs an IBar
public class Foo
{
  private IBar bar;

  public Foo(IBar bar)
  {
    this.bar = bar;
  }

  //...
}

Unless you really need an interface (the interface is used by more than one class), you MUST NOT USE IT. In this case, IBar allows utilizing any service class, that implements it. However, usually, this Interface will be used by a single class.

Why it is a bad idea to use an interface?. Because it is really hard to debug.

For example, let's say that the instance "bar" failed, question: which class failed?. Which code I should fix? A simple view, it leads to an Interface, and it's here where my road ends.

Instead, if the code uses a hard dependency then it's easy to debug a mistake.

//Foo Needs an IBar
public class Foo
{
  private BarService bar;

  public Foo(IBar bar)
  {
    this.bar = bar;
  }

  //...
}

If "bar" fails, then I should check and fir the class BarService.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionCharles GrahamView Question on Stackoverflow
Solution 1 - Design PatternstvanfossonView Answer on Stackoverflow
Solution 2 - Design PatternsJoelView Answer on Stackoverflow
Solution 3 - Design PatternsJeff SternalView Answer on Stackoverflow
Solution 4 - Design PatternsNathanView Answer on Stackoverflow
Solution 5 - Design PatternsGrant PalinView Answer on Stackoverflow
Solution 6 - Design PatternsNinineaView Answer on Stackoverflow
Solution 7 - Design PatternsTeoman shipahiView Answer on Stackoverflow
Solution 8 - Design PatternsNicholas BlumhardtView Answer on Stackoverflow
Solution 9 - Design PatternsNoelAdyView Answer on Stackoverflow
Solution 10 - Design PatternsblizpastaView Answer on Stackoverflow
Solution 11 - Design PatternsRomanView Answer on Stackoverflow
Solution 12 - Design PatternsDaniel BView Answer on Stackoverflow
Solution 13 - Design Patternsuser5474476View Answer on Stackoverflow
Solution 14 - Design PatternsYogeshView Answer on Stackoverflow
Solution 15 - Design PatternsGlenn MohammadView Answer on Stackoverflow
Solution 16 - Design PatternsmagallanesView Answer on Stackoverflow