Есть класс с интерфейсом EventSubscriberInterface, в нем методы getEventNames() и register(Provider $provider, ContainerInterface $container), в провайдере метод registerSubscriber() (или в кострукторе массив с сабскрайберами), котрый в массив с листенерами записывает сабскрайберы вместо листенеров, если вызван метод getListenersFor() проверяется перед отдачей листенера есть ли он объект с интерфейсом EventSubscriberInterface, если да, то регаем листенеры методом register и отдаем. Сами листенеры создаются в методе register, там же и дергается все из контейнера и инжектится. Как-то так. В итоге у нас листенеры создаются непосредственно при вызове событие, до этого регаются только сабскрайберы.