У цьому матеріалі поговоримо про реалізацію в Spring Framework принципу інверсії контролю (Inversion of Control, IoC). IoC також відомий як використання залежностей (DI). Це процес, при якому об'єкти визначають свої залежності (тобто інші об'єкти, з якими вони працюють) лише через аргументи конструктора, аргументи фабричного методу або властивості, які встановлюються на екземпляр об'єкта після створення або повернення фабричним методом. Потім контейнер впроваджує ці залежності під час створення біна. Цей процес за своєю суттю є інверсією (звідси і назва: інверсія контролю (Inversion of Control) самого біна, що самостійно контролює створення або розміщення його залежностей за допомогою прямої побудови класів або такого механізму, як шаблон локатора служб (Service Locator).

Пакети org.springframework.beans та org.springframework.context є основою для IoC-контейнера Spring Framework. Інтерфейс BeanFactory надає розширений механізм конфігурації, здатний керувати об'єктами будь-якого типу. ApplicationContext є підінтерфейсом BeanFactory. До нього додаються:

  • Простіша інтеграція з функціями АОП у Spring

  • Обробка ресурсів повідомлень (для використання в інтернаціоналізації)

  • Публікація подій

  • Контексти, специфічні для рівня програм, такі як WebApplicationContext для використання у вебдодатках.

Стисло, BeanFactory забезпечує основу конфігурації та базовий функціонал, а ApplicationContext додає більш специфічну корпоративну функціональність. ApplicationContext є повним розширеним набором BeanFactory і використовується виключно в цьому розділі при описі IoC-контейнера Spring. Для отримання додаткової інформації про використання BeanFactory замість ApplicationContext, дивись розділ, присвячений BeanFactory API.

У Spring об'єкти, які становлять основу твого додатка та управляються IoC-контейнером Spring, називаються бінами (beans). Бін (bean) — це об'єкт, який створюється, компонується та управляється IoC-контейнером Spring. В іншому випадку бін — це просто один із багатьох об'єктів у твоєму додатку. Біни та залежності між ними відображені в конфігураційних метаданих, які використовуються контейнером.

Коротко про контейнери

Інтерфейс org.springframework.context.ApplicationContext представляє IoC-контейнер Spring і відповідає за створення екземпляра, налаштування та компонування бінів. Контейнер отримує інструкції про те, які об'єкти створювати, конфігурувати та компонувати шляхом зчитування конфігураційних метаданих. Конфігураційні метадані представлені у вигляді XML, анотацій Java або Java коду. Це дозволяє виражати об'єкти, що становлять додаток, і багату взаємозалежність між цими об'єктами.

Кілька реалізацій інтерфейсу ApplicationContext постачаються разом зі Spring. В автономних програмах зазвичай створюється екземпляр ClassPathXmlApplicationContext або FileSystemXmlApplicationContext. Хоча XML є традиційним форматом для визначення конфігураційних метаданих, можна вказати контейнеру використовувати анотації Java або код як формат метаданих, надавши невеликий обсяг конфігурації XML для декларативного включення підтримки цих додаткових форматів метаданих.

У більшості сценаріїв застосування чіткий код користувача не потрібен для створення одного або декількох екземплярів IoC-контейнера Spring. Наприклад, у сценарії вебзастосунку зазвичай достатньо восьми (або близько того) рядків шаблону веб-дескриптора XML у файлі web.xml програми. Якщо ти використовуєш Spring Tools для Eclipse (середовище розробки на базі Eclipse), можеш легко створити цю стандартну конфігурацію кількома натисканнями мишки або клавіш.

На схемі нижче зображено високорівневе уявлення про те, як працює Spring. Класи програми об'єднуються з конфігураційними метаданими таким чином, що після створення та ініціалізації ApplicationContext ти отримуєш повністю налаштовану та виконувану систему або програму.

Конфігураційні метадані

Як показано на попередній схемі, IoC-контейнер Spring використовує форму конфігураційних метаданих. Ці конфігураційні метадані являють собою те, яким чином ти як розробник програми повідомляєш контейнеру Spring про те, як потрібно створювати, конфігурувати та компонувати об'єкти у додатку.

Конфігураційні метадані традиційно представлені у простому та інтуїтивно зрозумілому форматі XML, який і використовується в більшій частині цього розділу для пояснення ключових концепцій та можливостей контейнера Spring IoC.

Метадані на основі XML не є єдиною допустимою формою конфігураційних метаданих. Сам IoC-контейнер Spring повністю відокремлений від формату, де фактично записані конфігураційні метадані. У наші дні багато розробників вибирають конфігурацію на основі Java для своїх програм Spring.

Для отримання інформації про використання інших форм метаданих з контейнером Spring див. розділи:

  • Конфігурація на основі анотацій: У Spring 2.5 з'явилася підтримка конфігураційних метаданих на основі анотацій: Spring 2.5 introduced support for annotation-based configuration metadata.

  • Конфігурація на основі Java: Починаючи зі Spring 3.0, багато функцій, що надаються проєктом Spring JavaConfig, стали частиною ядра Spring Framework. Таким чином, можна визначати біни, які є зовнішніми по відношенню до класів твоєї програми, використовуючи Java, а не XML-файли. Щоб використовувати ці нові функції, звернися до анотацій @Configuration, @Bean, @Import та @DependsOn.

Конфігурація Spring складається мінімум з одного, але, як правило, все ж таки більш ніж одного визначення біна, якими контейнер повинен керувати. Конфігураційні метадані на основі XML налаштовують ці біни як елементи <bean/> всередині елемента <bean/> верхнього рівня. У конфігурації Java зазвичай використовуються методи з описом @Bean у класі @Configuration.

Ці визначення бінів відповідають фактичним об'єктам, з яких складається додаток. Як правило ти визначаєш об'єкти рівня служб, об'єкти доступу до даних (DAO), об'єкти подання, такі як екземпляри Struts Action, об'єкти інфраструктури, такі як Hibernate SessionFactories, JMS Queues тощо. Зазвичай деталізовані об'єкти домену в контейнері не налаштовуються, оскільки за створення та завантаження об'єктів домену зазвичай відповідають DAO та бізнес-логіка. Однак ти можеш використовувати інтеграцію Spring з AspectJ для конфігурування об'єктів, які були створені поза контролем IoC-контейнера.

У наступному прикладі показано базову структуру конфігураційних метаданих на основі XML:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="..." class="...">  
        <!-- об'єкти, що взаємодіють (collaborators) і конфігурація для цього біна знаходяться тут -->
    </bean>
    <bean id="..." class="...">
        <!-- об'єкти, що взаємодіють (collaborators) і конфігурація для цього біна знаходяться тут -->
    </bean>
    <!-- ще визначення бінів дивіться тут -->
</beans>
  1. Атрибут id — це рядок, який ідентифікує визначення окремого бина.
  2. Атрибут class визначає тип біна та використовує повне ім'я класу.

Значення атрибуту id стосується об'єктів, що взаємодіють. XML для посилання на об'єкти, що взаємодіють, в цьому прикладі не показано.