Контейнер дозволяє залежність біна таким чином:

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