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 может быть использована для предоставления псевдонимов.