Spring IoC контейнер: процесс разрешения зависимостей
Контейнер выполняет разрешение зависимостей бина следующим образом:
- ApplicationContext создается и инициализируется с метаданными конфигурации, которые описывают все компоненты. Метаданные конфигурации могут быть указаны с помощью XML, кода Java или аннотаций.
- Для каждого компонента его зависимости выражаются в форме свойств, аргументов конструктора или аргументов метода статичной фабрики (если вы используете его вместо обычного конструктора). Эти зависимости предоставляются компоненту, когда компонент фактически создается.
- Каждый аргумент свойства или конструктора является фактическим определением значения, которое нужно установить, или ссылкой на другой компонент в контейнере.
- Каждый аргумент свойства или конструктора, являющийся значением, преобразуется из указанного формата в фактический тип аргумента этого свойства или конструктора. По умолчанию Spring может преобразовать значение, предоставленное в строковом формате, во все встроенные типы, такие как int, long, String, boolean и т. д.
Контейнер Spring проверяет конфигурацию каждого компонента при создании контейнера. Однако сами свойства компонента не устанавливаются, пока компонент не будет создан. Бины с одноэлементной областью и предварительно созданным экземпляром (по умолчанию) создаются при создании контейнера. Области определены в Bean Scopes. В противном случае бин создается только тогда, когда он запрашивается. Создание bean-компонента потенциально может привести к созданию графа bean-компонентов, поскольку создаются и назначаются зависимости bean-компонента и его зависимости (и т. д.). Обратите внимание, что несоответствие разрешения среди этих зависимостей может проявиться поздно, то есть при первом создании затронутого компонента.
Круговые зависимости
Если вы используете преимущественно внедрение в конструкторе, можно создать неразрешимый сценарий циклической зависимости.
Например: класс A требует экземпляр класса B с помощью инжектора конструктора, а класс B требует экземпляр класса A с помощью инжектора конструктора. Если вы настраиваете bean-компоненты для классов A и B, которые будут внедряться друг в друга, контейнер IoC Spring обнаруживает эту циклическую ссылку во время выполнения и генерирует исключение BeanCurrentlyInCreationException.
Одним из возможных решений является редактирование исходного кода некоторых классов для настройки сеттерами, а не конструкторами. В качестве альтернативы, избегайте инъекции конструктора и используйте только инъекцию сеттера. Другими словами, хотя это и не рекомендуется, вы можете настраивать циклические зависимости с помощью установки сеттера.
В отличие от типичного случая (без циклических зависимостей), циклическая зависимость между bean-компонентом A и bean-компонентом B заставляет один из bean-компонентов быть введенным в другой до полной инициализации (классический сценарий типа "курица и яйцо").
Как правило, вы можете доверять Spring, чтобы поступать правильно. Он обнаруживает проблемы конфигурации, такие как ссылки на несуществующие компоненты и циклические зависимости, во время загрузки контейнера. Spring устанавливает свойства и разрешает зависимости как можно позже, когда бин фактически создается. Это означает, что правильно загруженный контейнер Spring может впоследствии сгенерировать исключение, когда вы запрашиваете объект, если существует проблема с созданием этого объекта или одной из его зависимостей - например, бин выдает исключение в результате отсутствия или недопустимого свойства. Эта потенциально задержанная видимость некоторых проблем конфигурации является причиной того, что реализации ApplicationContext по умолчанию предварительно создают одноэлементные компоненты. За счет некоторого времени и памяти для создания этих bean-компонентов до того, как они действительно понадобятся, вы обнаружите проблемы конфигурации при создании ApplicationContext, а не позднее. Вы по-прежнему можете переопределить это поведение по умолчанию, чтобы синглтон-бины инициализировались лениво, а не были предварительно созданы.
Если не существует циклических зависимостей, когда один или несколько взаимодействующих bean-компонентов вводятся в зависимый bean-компонент, каждый сотрудничающий bean-компонент полностью настраивается перед вводом в зависимый bean-компонент. Это означает, что, если компонент A имеет зависимость от компонента B, контейнер Spring IoC полностью настраивает компонент B перед вызовом метода сеттера для компонента A. Другими словами, экземпляр компонента создается (если он не является предварительно созданным синглтоном), его зависимости установлены, и соответствующие методы жизненного цикла (такие как настроенный метод init или метод обратного вызова InitializingBean) вызываются.
Читайте также:
- Spring IoC контейнер: DI на основе конструктора или сеттера?
- Spring IoC контейнер: внедрение зависимостей на основе конструктора
- Spring IoC контейнер: внедрение зависимостей на основе сеттера
Комментарии
Отправить комментарий