diff --git a/service_container/service_locators.rst b/service_container/service_locators.rst
new file mode 100644
index 00000000000..25ee199efef
--- /dev/null
+++ b/service_container/service_locators.rst
@@ -0,0 +1,226 @@
+.. index::
+ single: DependencyInjection; Service Locators
+
+Service Locators
+================
+
+Sometimes, a service needs access to several other services without being sure
+that all of them will actually be used. In those cases, you may want the
+instantiation of the services to be lazy. However, that's not possible using
+the explicit dependency injection since services are not all meant to
+be ``lazy`` (see :doc:`/service_container/lazy_services`).
+
+A real-world example are applications that implement the `Command pattern`_
+using a CommandBus to map command handlers by Command class names and use them
+to handle their respective command when it is asked for::
+
+ // ...
+ class CommandBus
+ {
+ /**
+ * @var CommandHandler[]
+ */
+ private $handlerMap;
+
+ public function __construct(array $handlerMap)
+ {
+ $this->handlerMap = $handlerMap;
+ }
+
+ public function handle(Command $command)
+ {
+ $commandClass = get_class($command)
+
+ if (!isset($this->handlerMap[$commandClass])) {
+ return;
+ }
+
+ return $this->handlerMap[$commandClass]->handle($command);
+ }
+ }
+
+ // ...
+ $commandBus->handle(new FooCommand());
+
+Considering that only one command is handled at a time, instantiating all the
+other command handlers is unnecessary. A possible solution to lazy-load the
+handlers could be to inject the whole dependency injection container::
+
+ use Symfony\Component\DependencyInjection\ContainerInterface;
+
+ class CommandBus
+ {
+ private $container;
+
+ public function __construct(ContainerInterface $container)
+ {
+ $this->container = $container;
+ }
+
+ public function handle(Command $command)
+ {
+ $commandClass = get_class($command)
+
+ if ($this->container->has($commandClass)) {
+ $handler = $this->container->get($commandClass);
+
+ return $handler->handle($command);
+ }
+ }
+ }
+
+However, injecting the entire container is discouraged because it gives too
+broad access to existing services and it hides the actual dependencies of the
+services.
+
+**Service Locators** are intended to solve this problem by giving access to a
+set of predefined services while instantiating them only when actually needed.
+
+Defining a Service Locator
+--------------------------
+
+First, define a new service for the service locator. Use its ``arguments``
+option to include as many services as needed to it and add the
+``container.service_locator`` tag to turn it into a service locator:
+
+.. configuration-block::
+
+ .. code-block:: yaml
+
+ services:
+
+ app.command_handler_locator:
+ class: Symfony\Component\DependencyInjection\ServiceLocator
+ tags: ['container.service_locator']
+ arguments:
+ -
+ AppBundle\FooCommand: '@app.command_handler.foo'
+ AppBundle\BarCommand: '@app.command_handler.bar'
+
+ .. code-block:: xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ .. code-block:: php
+
+ use Symfony\Component\DependencyInjection\ServiceLocator;
+ use Symfony\Component\DependencyInjection\Reference;
+
+ //...
+
+ $container
+ ->register('app.command_handler_locator', ServiceLocator::class)
+ ->addTag('container.service_locator')
+ ->setArguments(array(array(
+ 'AppBundle\FooCommand' => new Reference('app.command_handler.foo'),
+ 'AppBundle\BarCommand' => new Reference('app.command_handler.bar'),
+ )))
+ ;
+
+.. note::
+
+ The services defined in the service locator argument must include keys,
+ which later become their unique identifiers inside the locator.
+
+Now you can use the service locator injecting it in any other service:
+
+.. configuration-block::
+
+ .. code-block:: yaml
+
+ services:
+
+ AppBundle\CommandBus:
+ arguments: ['@app.command_handler_locator']
+
+ .. code-block:: xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+ .. code-block:: php
+
+ use AppBundle\CommandBus;
+ use Symfony\Component\DependencyInjection\Reference;
+
+ //...
+
+ $container
+ ->register(CommandBus::class)
+ ->setArguments(array(new Reference('app.command_handler_locator')))
+ ;
+
+.. tip::
+
+ If the service locator is not intended to be used by multiple services, it's
+ better to create and inject it as an anonymous service.
+
+Usage
+-----
+
+Back to the previous CommandBus example, it looks like this when using the
+service locator::
+
+ // ...
+ use Psr\Container\ContainerInterface;
+
+ class CommandBus
+ {
+ /**
+ * @var ContainerInterface
+ */
+ private $handlerLocator;
+
+ // ...
+
+ public function handle(Command $command)
+ {
+ $commandClass = get_class($command);
+
+ if (!$this->handlerLocator->has($commandClass)) {
+ return;
+ }
+
+ $handler = $this->handlerLocator->get($commandClass);
+
+ return $handler->handle($command);
+ }
+ }
+
+The injected service is an instance of :class:`Symfony\\Component\\DependencyInjection\\ServiceLocator`
+which implements the PSR-11 ``ContainerInterface``, but it is also a callable::
+
+ // ...
+ $locateHandler = $this->handlerLocator;
+ $handler = $locateHandler($commandClass);
+
+ return $handler->handle($command);
+
+.. _`Command pattern`: https://en.wikipedia.org/wiki/Command_pattern