Spring IoC контейнер: точки расширения контейнера, BeanPostProcessor

Как правило, разработчику приложений не нужно создавать подклассы классов реализации ApplicationContext. Вместо этого контейнер Spring IoC можно расширить, подключив реализации специальных интеграционных интерфейсов.

Настройка Beans с помощью BeanPostProcessor

Интерфейс BeanPostProcessor определяет методы обратного вызова, которые вы можете реализовать, чтобы предоставить собственную (или переопределить контейнерную логику) реализацию, логику разрешения зависимостей и т. д. Если вы хотите реализовать некоторую пользовательскую логику после того, как контейнер Spring завершит создание экземпляра, настройку и инициализацию компонента, вы можете подключить одну или несколько пользовательских реализаций BeanPostProcessor.

Вы можете настроить несколько экземпляров BeanPostProcessor и управлять порядком, в котором эти экземпляры BeanPostProcessor выполняются, установив свойство order. Вы можете установить это свойство, только если BeanPostProcessor реализует интерфейс Ordered. Если вы пишете свой собственный BeanPostProcessor, вам следует подумать о реализации интерфейса Ordered.

Экземпляры BeanPostProcessor работают с экземплярами bean (или объекта). То есть контейнер Spring IoC создает экземпляр компонента, а затем экземпляры BeanPostProcessor выполняют свою работу.

Экземпляры BeanPostProcessor ограничены для каждого контейнера. Это актуально, только если вы используете контейнерные иерархии. Если вы определите BeanPostProcessor в одном контейнере, он постобработает только bean-компоненты в этом контейнере. Другими словами, bean-компоненты, определенные в одном контейнере, не подвергаются пост-обработке BeanPostProcessor, определенным в другом контейнере, даже если оба контейнера являются частью одной и той же иерархии.

Чтобы изменить фактическое определение компонента (то есть план, определяющий компонент), вам вместо этого необходимо использовать BeanFactoryPostProcessor.

Интерфейс org.springframework.beans.factory.config.BeanPostProcessor состоит ровно из двух методов обратного вызова. Когда такой класс регистрируется в качестве постпроцессора в контейнере, для каждого экземпляра бина, созданного контейнером, постпроцессор получает обратный вызов из контейнера как до методов инициализации контейнера (таких как InitializingBean.afterPropertiesSet() или любой объявленный метод init), и после любых обратных вызовов инициализации бина. Постпроцессор может выполнять любые действия с экземпляром компонента, включая полное игнорирование обратного вызова. Постпроцессор бина обычно проверяет наличие интерфейсов обратного вызова или может обернуть бин прокси. Некоторые классы инфраструктуры Spring AOP реализованы в виде постпроцессоров бинов, чтобы обеспечить логику прокси-упаковки.

ApplicationContext автоматически обнаруживает любые bean-компоненты, определенные в метаданных конфигурации, которые реализуют интерфейс BeanPostProcessor. ApplicationContext регистрирует эти bean-компоненты как постпроцессоры, чтобы их можно было вызывать позже при создании bean-компонента. Постпроцессоры bean-компонентов могут быть развернуты в контейнере так же, как и любые другие bean-компоненты.

Обратите внимание, что при объявлении BeanPostProcessor с использованием метода фабрики @Bean в классе конфигурации типом возвращаемого значения метода фабрики должен быть сам класс реализации или, по крайней мере, интерфейс org.springframework.beans.factory.config.BeanPostProcessor, указывающий на постпроцессорную природу этого компонента. В противном случае ApplicationContext не сможет автоматически определить его по типу до его полного создания. Поскольку BeanPostProcessor необходимо создать на ранней стадии, чтобы применить к инициализации других bean-компонентов в контексте, это раннее обнаружение типа является критическим.

Программная регистрация экземпляров BeanPostProcessor

Хотя рекомендуемый подход для регистрации BeanPostProcessor заключается в автоопределении ApplicationContext, вы можете программно зарегистрировать их в ConfigurableBeanFactory с помощью метода addBeanPostProcessor. Это может быть полезно, когда вам нужно оценить условную логику перед регистрацией или даже для копирования постпроцессоров бина в контекстах иерархии. Однако обратите внимание, что экземпляры BeanPostProcessor, добавленные программным способом, не соответствуют интерфейсу Ordered. Здесь порядок регистрации определяет порядок исполнения. Также обратите внимание, что экземпляры BeanPostProcessor, зарегистрированные программно, всегда обрабатываются раньше, чем экземпляры, зарегистрированные с помощью автоопределения, независимо от какого-либо явного упорядочения.

Экземпляры BeanPostProcessor и автоматическое проксирование AOP

Классы, которые реализуют интерфейс BeanPostProcessor, являются специальными и обрабатываются контейнером по-разному. Все экземпляры BeanPostProcessor и компоненты, на которые они напрямую ссылаются, создаются при запуске как часть специальной фазы запуска ApplicationContext. Затем все экземпляры BeanPostProcessor регистрируются отсортированным образом и применяются ко всем другим bean-компонентам в контейнере. Поскольку автоматическое проксирование AOP реализовано как сам BeanPostProcessor, ни экземпляры BeanPostProcessor, ни компоненты, на которые они напрямую ссылаются, не имеют права на автоматическое проксирование и, таким образом, не имеют вплетенных в них аспектов.

Для любого такого компонента вы должны увидеть информационное сообщение журнала: Bean someBean не подходит для обработки всеми интерфейсами BeanPostProcessor (например, не подходит для автоматического проксирования (not eligible for auto-proxying)).

Если у вас есть bean-компоненты, подключенные к вашему BeanPostProcessor с помощью autowiring или @Resource (что может привести к автоматическому подключению), Spring может получить доступ к неожиданным bean-компонентам при поиске кандидатов на зависимости соответствия типа и, следовательно, лишить их права на автоматическое проксирование или другие виды постобработки бинов. Например, если у вас есть зависимость, аннотированная @Resource, где имя поля или сеттера не соответствует напрямую объявленному имени компонента, и атрибут name не используется, Spring обращается к другим компонентам для сопоставления их по типу.


Читайте также:


Комментарии

Популярные сообщения из этого блога

Методы класса Object в Java

Как получить текущий timestamp в Java

Основные опции JVM для повышения производительности и отладки