IoC-контейнер Spring управляє одним або декількома бінами. Ці біни створюються за допомогою конфігураційних метаданих, які ти надаєш контейнеру (наприклад, у вигляді XML-визначень <bean/>).

У самому контейнері ці визначення бінів представлені як об'єкти BeanDefinition, що містять (серед іншої інформації) такі метадані:

  • Повне ім'я класу із зазначенням пакета: зазвичай це фактичний клас реалізації біна, що визначається.

  • Елементи поведінкової конфігурації біна, які визначають те, як бін повинен вести себе в контейнері (область дії, зворотні виклики життєвого циклу тощо).

  • Посилання на інші біни, які необхідні для його роботи. Ці посилання також називаються об'єктами, що взаємодіють (collaborators) або залежностями (dependencies).

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

Ці метадані перетворюються на набір властивостей, які становлять визначення кожного біна. У наведеній нижче таблиці описано такі властивості:

Таблиця 1. Визначення біна
Властивість Пояснюється в...

Клас

Створення бінів

Ім'я

Назва бінів

Область застосування

Області видимості біна

Аргументи конструктора

Впровадження залежностей

Властивості

Впровадження залежностей

Режим автоматичного виявлення та зв'язування

Взаємодіючі об'єкти з автоматичним виявленням та зв'язуванням

Режим відкладеної ініціалізації

Біни з відкладеною ініціалізацією

Метод ініціалізації

Зворотні виклики ініціалізації

Метод знищення

Зворотні виклики знищення

На додаток до визначення бінів, які містять інформацію про те, як створити конкретний бін, реалізації ApplicationContext також дозволяють реєструвати існуючі об'єкти, які створюються поза контейнером (користувачами). Це можна здійснити шляхом звернення до BeanFactory ApplicationContext через метод getBeanFactory(), який повертає реалізацію DefaultListableBeanFactory. DefaultListableBeanFactory підтримує цю реєстрацію через методи registerSingleton(..) та registerBeanDefinition(..). Однак типові додатки працюють виключно з бінами, визначеними за допомогою стандартних метаданих визначення бінів.

Метаданні бінів та екземпляри-одинаки, що надаються вручну, мають бути зареєстровані якнайшвидше, щоб контейнер міг правильно обробити їх під час автоматичного виявлення та зв'язування та інших етапів інтроспекції. Хоча перевизначення існуючих метаданих та існуючих екземплярів-одинаків і підтримується певною мірою, реєстрація нових бінів під час виконання (одночасно з прямим доступом до фабрики) офіційно не підтримується і може призвести до виключень одночасного доступу, несумісного стану в контейнері бінів або обох цих винятків.

Найменування бінів

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

В конфігураційних метаданих на основі XML використовується атрибут id, атрибут name або обидва для завдання ідентифікаторів біна. Атрибут id дозволяє встановити лише один ідентифікатор. Зазвичай ці імена є літерно-цифровими ('myBean', 'someService' тощо), але вони можуть містити спеціальні символи. Якщо хочеш ввести інші псевдоніми для біна, то також можеш вказати їх в атрибуті name, відокремивши комою (,), крапкою з комою (; ) або пробілом. Історична довідка: у версіях до Spring 3.1 атрибут id було визначено як тип xsd:ID, що обмежувало застосування символів. Починаючи з версії 3.1 він визначається як тип xsd:string. Зверни увагу, що унікальність id біна все ще забезпечується контейнером, але вже не є аналізаторами XML.

Не потрібно вказувати name або id для біна. Якщо явно не встановити name або id, контейнер згенерує унікальне ім'я для цього біна. Однак якщо хочеш посилатися на цей бін на ім'я, використовуючи елемент ref або пошук у стилі локатора служб (Service Locator), то маєш вказати ім'я. Мотиви відмови від вказання імені пов'язані з використанням внутрішніх бінів та об'єктів, що взаємодіють, з автоматичним виявленням та зв'язуванням.

Угоди про найменування бінів

Угода полягає у використанні типової угоди Java для іменування полів екземпляра при іменуванні бінів. Тобто імена бінів починаються з рядкової літери і продовжуються в camelCase (верблюжому) регістрі. Прикладами таких імен є accountManager, accountService, userDao, loginController тощо.

Послідовне найменування бінів робить конфігурацію більш легкою для читання та розуміння. До того ж, якщо ти користуєшся АОП у Spring, це дуже допомагає при застосуванні порад (advice) до набору бінів, пов'язаних за ім'ям.

За допомогою сканування компонентів зі шляхом класу (classpath), Spring генерує імена бінів для неназваних компонентів, дотримуючись правил, описаних раніше. По суті, береться просте ім'я класу, а його початковий символ переводиться до нижнього регістру. Однак у особливому випадку, коли є більше одного символу, а перший і другий символи знаходяться у верхньому регістрі, вихідний регістр зберігається. Це ті самі правила, які визначені в java.beans.Introspector.decapitalize (який Spring використовує тут).

Привласнення псевдоніму біну поза визначенням біна

У самому визначенні біна можна вказати більше одного імені для нього, використовуючи комбінацію з одного імені, вказаного атрибутом id, та будь-якої кількості інших імен в атрибуті name. Ці імена можуть бути еквівалентними псевдонімами одного і того ж біна і корисними в деяких ситуаціях. Наприклад, коли кожен компонент у додатку посилається на загальну залежність, використовуючи ім'я біна, специфічне для цього компонента. Однак встановлення всіх псевдонімів, у яких фактично визначено бін, не завжди є достатнім. Іноді бажано запровадити псевдонім для біна, визначеного в іншому місці. Це зазвичай зустрічається у великих системах, де конфігурація розділена між кожною підсистемою, а кожна підсистема має власний набір визначень об'єктів. У конфігураційних метаданих на основі XML для цього можна використовувати елемент <alias/>. У цьому прикладі показано, як це зробити:

 <alias name="fromName" alias="toName"/>

У цьому випадку бін (у тому ж контейнері) з ім'ям fromName — після використання цього визначення псевдоніма — може згадуватись як toName.

Наприклад, конфігураційні метадані для підсистеми A можуть посилатися на джерело даних DataSource під ім'ям subsystemA-dataSource. Конфігураційні метадані підсистеми B можуть посилатися на джерело даних DataSource під ім'ям subsystemB-dataSource. Під час створення основної програми, що використовує обидві підсистеми, основна програма звертається до джерела даних DataSource під ім'ям myApp-dataSource. Щоб усі три імені посилалися на один і той же об'єкт, можна додати такі визначення псевдонімів до конфігураційних метаданих:


<alias name ="myApp-dataSource" alias="subsystemA-dataSource"/>
<alias name="myApp-dataSource" alias="subsystemB-dataSource"/>

Тепер кожен компонент і основна програма можуть звертатися до dataSource за ім'ям, яке є унікальним і гарантовано не конфліктуватиме з жодним іншим визначенням (ефективно створюючи простір імен), але водночас вони звертаються до одного й того ж біна.

Java-конфігурація

Якщо ти використовуєш Javaconfiguration, анотація @Bean може бути використана для надання псевдонімів.