Контейнер выполняет разрешение зависимостей бина следующим образом:

  • ApplicationContext создается и инициализируется при помощи конфигурационных метаданных, которые описывают все бины. Конфигурационные метаданные могут быть заданы с помощью XML, кода Java или аннотаций.

  • Для каждого бина его зависимости выражаются в виде свойств, аргументов конструктора или аргументов статического фабричного метода (если вы используете его вместо обычного конструктора). Эти зависимости предоставляются бину при его фактическом создании.

  • Каждое свойство или аргумент конструктора представляет собой фактическое определение значения, которое нужно установить, или ссылку на другой бин в контейнере.

  • Каждое свойство или аргумент конструктора, являющийся значением, преобразуется из заданного формата в фактический тип этого свойства или аргумента конструктора. По умолчанию Spring может преобразовать значение, предоставленное в строковом формате, во все встроенные типы, такие как int, long, String, boolean и так далее.

Контейнер Spring проверяет конфигурацию каждого бина при создании контейнера. Однако сами свойства бина не устанавливаются до тех пор, пока бин не будет создан. Бины, входящие в область видимости singleton и настроенные на предварительное создание экземпляра (pre-instantiated) (по умолчанию), создаются при создании контейнера. В противном случае бин создается только тогда, когда поступает запрос. Создание бина потенциально приводит к созданию графа зависимости бинов, поскольку создаются и назначаются зависимости бина, зависимости его зависимостей (и так далее). Обратите внимание, что несоответствия в разрешении этих зависимостей могут проявиться поздно, то есть при первом создании затронутого бина.

Циклические зависимости

Если вы используете преимущественно внедрение через конструктор, можно создать неразрешимый сценарий циклической зависимости.

Например: Класс A требует экземпляр класса B через внедрение на основе конструктора, а класс B требует экземпляр класса A через внедрение на основе конструктора. Если сконфигурировать бины классов A и B на внедрение друг в друга, IoC-контейнер Spring обнаружит эту циклическую ссылку во время выполнения и сгенерирует исключение BeanCurrentlyInCreationException.

Одним из возможных решений является редактирование исходного кода некоторых классов, чтобы конфигурирование осуществлялось с помощью сеттеров, а не конструкторов. Как вариант, избегайте внедрение зависимости через конструктор и используйте исключительно внедрение через сеттер. Иными словами, хотя это и не рекомендуется, можно настроить циклические зависимости с помощью внедрения через сеттер.

В отличие от типичного случая (без циклических зависимостей), циклическая зависимость между бином A и бином B заставляет один из бинов быть внедренным в другой до того, как сам будет полностью инициализирован (классический сценарий типа "курица и яйцо (причины и следствия)").

Как правило, можно довериться Spring в том, что все будет сделано верно. Он обнаруживает проблемы конфигурации, такие как ссылки на несуществующие бины и циклические зависимости, во время загрузки контейнера. Spring задаёт свойства и разрешает зависимости как можно позже, когда бин уже создан. Это означает, что контейнер Spring, который загрузился правильно, может позже сгенерировать исключение при запросе объекта, если существует проблема создания этого объекта или одной из его зависимостей - например, бин генерирует исключение в результате отсутствия или недопустимого свойства. Эта потенциально отложенная видимость некоторых проблем конфигурации является причиной того, что реализации ApplicationContext по умолчанию предварительно создают экземпляры бинов-одиночек. Затратив некоторое время и память на создание этих бинов до того, как они действительно понадобятся, вы обнаружите проблемы с конфигурацией при создании ApplicationContext, а не позже. Вы по-прежнему можете переопределить это поведение по умолчанию, чтобы бины-одиночки инициализировались отложено вместо как можно более быстрого предварительного создания экземпляра.

Если циклических зависимостей не существует, то при внедрении одного или нескольких взаимодействующих бинов в зависимый бин, каждый взаимодействующий бин полностью конфигурируется перед внедрением в зависимый бин. Это означает, что если бин A зависит от бина B, IoC-контейнер Spring полностью конфигурирует бин B перед вызовом сеттера для бина A. Иными словами, создается экземпляр бина (если он не является предварительно созданной одиночкой), устанавливаются его зависимости, и вызываются соответствующие методы жизненного цикла (такие как сконфигурированный метод init или метод обратного вызова InitializingBean).