365

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?

Bogdan Verbenets
  • 25,686
  • 13
  • 66
  • 119
Charles Graham
  • 24,293
  • 14
  • 43
  • 56
  • 16
    Inversion of control means that "an object should not know how to construct its dependencies"?!? That one is new to me. No, really, that's not what "inversion of control" means. See http://martinfowler.com/bliki/InversionOfControl.html That article even provides references for the etymology of the term, dating back to the 1980s. – Rogério Feb 18 '10 at 01:34
  • 1
    Answer here: http://www.infoq.com/articles/Succeeding-Dependency-Injection – Mark Seemann Nov 27 '13 at 08:24
  • 4
    Mark Seemann argues Service Locator as anti-pattern(http://blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Pattern/). Also, I found the diagram (found here, http://stackoverflow.com/a/9503612/1977871) helpful to understand the DI and SL predicament. Hope this helps. – VivekDev Jan 11 '16 at 08:12
  • Thanks will take a look. I remember singletons are anti-pattern and everyone uses them. – Zippy Apr 16 '22 at 14:24

16 Answers16

238

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.

user2340612
  • 10,053
  • 4
  • 41
  • 66
tvanfosson
  • 524,688
  • 99
  • 697
  • 795
  • 27
    Additionally, you can use both when constructing a class. The default constructor can use the SL to retrieve the dependencies, and pass them to the "real" constructor which receives those dependencies. You get the best of both worlds. – Grant Palin Oct 15 '09 at 17:15
  • 8
    No, the ServiceLocator is the one responsible for instantiating the correct implementation for a given dependency (plugin). In the case of DI, the DI "container" is the one responsible for that. – Rogério Feb 18 '10 at 01:37
  • 6
    @Rogerio yes but the the class still has to know about the Service Locator... thats two depenencies. Also more often than not I have seen Service Locator delegate to the DI container for lookup particularly for transient objects that need service support. – Adam Gent Feb 06 '13 at 23:08
  • 2
    @Adam I didn't say that the Service Locator would delegate to a DI container. These are two mutually exclusive patterns, as described in the ["official" article](http://martinfowler.com/articles/injection.html). To me, Service Locator has a huge advantage over DI in practice: use of a DI container invites abuse (which I've seen repeatedly), while use of a Service Locator does not. – Rogério Feb 07 '13 at 11:13
  • 2
    @Rogerio I have had the complete opposite experience and have seen the service locator completely abused particularly if your writing more component/service orient where its less object oriented and more separation of behavior and state. The service locator pattern is very popular for people who like traditional object oriented programming (e.g. Active Record pattern vs DAO/Repository pattern). In the past this has not scaled for me particularly in a message passing architecture. You'll have to show me proof of the abuse. – Adam Gent Feb 07 '13 at 13:49
  • 2
    @Adam Regarding proof of DI abuse, I don't know of any such codebase that is publicly available. In commercial applications I have seen or participated (Java and C#.NET), usage of DI apparently occurred only for political reasons (some companies even *mandate* that all new projects use some DI container). There were literally hundreds of components with separate interfaces but only a single implementation, and no real expectation that additional implementations were ever going to appear. From my experience, this seems to be quite common in the IT industry, but maybe you were more lucky than I. – Rogério Feb 07 '13 at 14:05
  • 1
    @Rogerio Ahh yes... I have seen that happen. Where you have interface hell. I hardly ever use interfaces but for some reason people think you need them for good design. Also people think they are needed in DI for AOP (because of dynamic proxies) but that is not true. Speaking of AOP I can avoid a large part of DI and Service Locator pattern using AspectJ but thats a story for another time... – Adam Gent Feb 07 '13 at 14:13
  • 1
    @Rogério most DI containers will allow you to register a dependency as itself. This avoids the need to create an interface just for the sake of being able to inject it. I use this often when that makes sense, being careful to define the methods as virtual so that they can still be easily mocked by mocking frameworks. – tvanfosson Feb 03 '14 at 20:07
  • 4
    "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." Not true. In your unit tests, a call to a register function in the service locator container can be used to easily add mocks to the registry. – Drumbeg Mar 21 '14 at 10:15
  • 1
    @Drumbeg but with constructor injection I don't have to worry about any extraneous configuration; I call that easier – tvanfosson Mar 21 '14 at 13:20
  • In my implementation, if I build a mock in my test, all I have to do is register it like so: Container::register('class_name', mockObject);. This is an extra line of code in your test in place of just passing the mock into the constructor, but I wouldn't say that constructor injection makes things much easier to test. I guess it depends on your implementation of the container class. – Drumbeg Mar 21 '14 at 15:19
  • 2
    @Drumbeg - ok, now change it to use a different locator or change how the locator does registration. See there's the problem with service locator - you've coupled your implementation and your tests to something not required for the actual work your class does, only it's configuration. – tvanfosson Mar 21 '14 at 18:50
  • 1
    @tvanfosson My point was that using a service locator does not make testing the classes difficult. – Drumbeg Mar 24 '14 at 09:29
  • This answer does not describe the essence of what a service locator is or why it is a problem. A class that creates its dependencies internally is not by definition a service locator. See Jeff Sternal's answer below. –  May 15 '18 at 15:25
117

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.

Joel
  • 11,431
  • 17
  • 62
  • 72
  • 21
    But how do you handle the case where you have to create objects during runtime? If you create them manually with "new" you cannot make use of DI. If you call the DI framework for help, you're breaking the pattern. So what options are left? – Boris Apr 10 '13 at 14:35
  • 11
    @Boris I had the same problem and decided to inject class specific factories. Not pretty but got the job done. Would love to see a prettier solution. – Charlie Rudenstål Jan 09 '14 at 11:43
  • Direct link to comparison: http://martinfowler.com/articles/injection.html#ServiceLocatorVsDependencyInjection – Teoman shipahi Aug 03 '15 at 19:14
  • 2
    @Boris If I needed to construct new objects on the fly I would inject an Abstract Factory for said objects. Which would be similar to injecting a service locator in this instance but provides a concrete, uniform, compile-time, interface for building the relevant objects and makes the dependencies explicit. – NotVeryMoe Feb 27 '17 at 08:35
59

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.

Jeff Sternal
  • 47,787
  • 8
  • 93
  • 120
  • 3
    I prefer "Singletons Considered Stupid", http://steve.yegge.googlepages.com/singleton-considered-stupid – Charles Graham Oct 13 '09 at 02:05
  • 2
    I love ol' Steve Yegge and the title of that article is great, but I think the article I cited and Miško Hevery's "Singletons are Pathological liars" (http://misko.hevery.com/2008/08/17/singletons-are-pathological-liars/) make a better case against the particular devilry of service locator. – Jeff Sternal Oct 23 '09 at 19:49
  • This answer is the most correct because it best defines a service locator : "A class that hides its dependencies." Note that creating a dependency internally, while often not a good thing, does not make a class a service locator. Also, taking a dependency on a container is a problem but not "the" problem that most clearly defines a service locator. –  May 15 '18 at 15:21
  • 1
    `With dependency injection (at least constructor injection) the dependencies are explicit.`. Please explain. – FindOutIslamNow Jun 13 '18 at 11:51
  • 1
    As above, I cannot see how SL makes dependencies less explicit than DI... – Michał Powłoka Oct 29 '18 at 09:17
  • Service Locators do not have to be a singleton. Further, you can engineer them to throw compile-time errors instead of runtime errors that you'd get with DI.. Here is how I use them: https://github.com/cowwoc/pouch – Gili Nov 11 '22 at 07:28
57

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

Nathan
  • 2,705
  • 23
  • 28
  • Fantastic summary: "Service Locator and Dependency Injection are just implementations of Dependency Inversion Principle. " – Hans Oct 04 '15 at 11:42
  • 1
    And he states also : The key difference is that with a Service Locator every user of a service has a dependency to the locator. The locator can hide dependencies to other implementations, but you do need to see the locator. So the decision between locator and injector depends on whether that dependency is a problem. – programaths Jun 29 '16 at 07:19
  • 1
    ServiceLocator and DI have nothing to do with the "Dependency Inversion Principle" (DIP). DIP is a way to make a high-level component more reusable, by replacing a compile-time dependency on a low-level component with a dependency on an abstract type defined together with the high-level component, which gets implemented by the low-level component; in this way, the compile-time dependency gets inverted, as now it is the low-level one which depends on the high-level one. Also, note that Martin Fowler's article explains that DI and IoC are *not* the same thing. – Rogério Sep 26 '16 at 15:44
28

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.

Grant Palin
  • 4,546
  • 3
  • 36
  • 55
  • Interesting! I'm using both DI and SL, but not with two constructors. Three or four most boring often needed dependencies (settings, etc...) get obtained from the SL on the fly. Everything else gets constructor-injected. It's a bit ugly, but pragmatic. – maaartinus Nov 19 '17 at 14:32
19

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).

Eliahu Aaron
  • 4,103
  • 5
  • 27
  • 37
Nininea
  • 2,671
  • 6
  • 31
  • 57
  • Dependency Injection doesn't require the use of a DI Container though. With DI, a not-that-uncommon approach is to use [Pure DI](https://blog.ploeh.dk/2012/11/06/WhentouseaDIContainer/), which basically means you hand-wire your object graphs in the [Composition Root](https://freecontent.manning.com/dependency-injection-in-net-2nd-edition-understanding-the-composition-root/). – Steven Aug 17 '21 at 09:36
8

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!

Yogesh Umesh Vaity
  • 41,009
  • 21
  • 145
  • 105
Nicholas Blumhardt
  • 30,271
  • 4
  • 90
  • 101
8

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/

cngzz1
  • 143
  • 2
  • 9
Teoman shipahi
  • 47,454
  • 15
  • 134
  • 158
6

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.

NoelAdy
  • 224
  • 2
  • 5
5

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.

Eliahu Aaron
  • 4,103
  • 5
  • 27
  • 37
Roman
  • 431
  • 5
  • 11
5

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.

Yogesh Umesh Vaity
  • 41,009
  • 21
  • 145
  • 105
blizpasta
  • 2,624
  • 3
  • 25
  • 31
4

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.

Daniel B
  • 4,145
  • 1
  • 21
  • 21
  • 4
    Hmm I'd disagree: the service locator ex. clearly shows that there's still a dependency there... the service locator. If the `bar` class itself has a dependency, then `bar` will also have service locator, that's the whole point of using DI/IoC. – GFoley83 May 10 '14 at 00:49
4

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://learn.microsoft.com/zh-cn/dotnet/core/extensions/dependency-injection-guidelines#recommendations

user5474476
  • 141
  • 9
1

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.

Yogesh
  • 3,044
  • 8
  • 33
  • 60
0

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.

Glenn Mohammad
  • 3,871
  • 4
  • 36
  • 45
-3

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.

magallanes
  • 6,583
  • 4
  • 54
  • 55
  • 3
    A class is a blueprint to construct specific object. On the other hand an interface is a `contract` and just defines a behaviour not the action. Instead of passing around actual object, only the interface is shared so that the consumer doesn’t access the rest of your object. Also for unit testing it helps to test only the part that needs to be tested. I guess in time you’d understand its usefulness. – Gunhan Apr 29 '20 at 07:57