Статьи

Зависимости весны — противоположное направление, пожалуйста?

Здесь мы увидим, как управлять зависимостями между компонентами в контексте среды Spring, используя «противоположное направление» таких зависимостей.

Spring великолепен в обеспечении инверсии управляющего контейнера, создании экземпляров bean-компонентов, их подключении и управлении жизненным циклом. Но можно ли там улучшить?

Да, Spring Framework великолепен. Нет сомнения. Я помню то волнение, когда я играл с ним впервые (это было несколько лет назад). Было замечательно видеть, что после обеспечения правильной конфигурации волшебство произошло — все бины были созданы и, что более важно, они были соединены вместе контейнером …

В тот момент инверсия управления была довольно новой концепцией, и вещи, которыми занимался Spring, слишком сильно впечатлили нас. В то время мы завершили довольно большой продукт, который требовал сложной настройки компонентов и зависимостей между ними, и поэтому мы были полностью разочарованы тем, что Spring появился с опозданием.

Хорошо, весна отличная. Но определенно можно улучшить в некоторых областях. Оставим в покое только священные войны, связанные с Spring, и рассмотрим его базовую функциональность — контейнер IoC. В конце концов, это одна из основных концепций Spring — так что, возможно, мы сможем немного ее отшлифовать?

Давайте представим, что у нас есть два bean-компонента в контексте Spring — BeanA и BeanB. И у BeanA есть свойство, к которому должен быть подключен BeanB. Если мы исключим проблемы с автопроводкой, такая зависимость будет описана в XML-контексте Spring следующим образом:

<bean class="..." id="BeanA">
<property name="propertyThatRefersToB" ref="BeanB"/>
</bean>

<bean id="BeanB" class="..."/>

или это может быть еще короче, если используется пространство имен p: из Spring 2.x:

<bean class="..." id="BeanA" 
p:propertyThatRefersToB-ref="BeanB"/>

В общем, этот способ проинструктировать Spring, как вводить BeanB в BeanA, довольно хорош и более чем достаточен в большинстве ситуаций.

К сожалению, не во всех.

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

Недавно в одном из проектов, которые мы разрабатываем здесь в
SoftAMIS, у нас возникла та же проблема — вся система должна поддерживать динамически загружаемые плагины (фактически, все приложение можно рассматривать как набор плагинов) и, что более важно, вообще говоря , этот набор плагинов неизвестен, поэтому новые плагины могут быть добавлены позже, а существующие могут быть отключены.

Это был тот случай, когда Spring контейнер просто может выйти из строя …

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

Однако здесь у нас все еще были небольшие проблемы — весной, чтобы сделать ссылку на боб, вам нужно знать имя этого боба. Это было явно неприемлемо для плагинов — и нам была нужна возможность указать эту ссылку не на родительский бин (BeanA), а на бин, на который ссылается — (BeanB).

Таким образом, вместо направления ссылок сверху вниз нам понадобился противоположный, который предполагает, что непосредственно в бине мы можем указать, куда нужно вводить. Следующая картина иллюстрирует такую ​​разницу между этими подходами:

Разница между направлениями зависимости

Мы пытались найти готовое решение для этого, но не нашли ничего, что могло бы удовлетворить наши потребности (учтите, что на самом деле существуют более сложные типы ссылок между компонентами — например, через список, карту и набор).

Итак, необходимость — это мать прогресса — и мы создали небольшую библиотеку, которая позволяет делать такие противоположные инъекции весной.

Благодаря поддержке пользовательских пространств имен в Spring 2.x, полученная разметка оказалась довольно простой. Как это:

<bean class="..." id="BeanA"/>

<bean class="..." id="BeanB">
<inject:to-ref target="BeanA" name="propertyThatRefersToB"/>
</bean>

Довольно просто, правда? Обратите внимание на тег из пользовательского пространства имен (поддерживается Spring 2.x):

<inject:to-ref target="BeanA" name="propertyThatRefersToB"/>

Используя его сейчас, мы просто перевернули направление, в котором мы объявляем ссылки между bean-компонентами в контексте Spring — BeanA просто можно рассматривать как точку расширения, к которой может быть подключен базовый BeanB. И подумайте о том, чтобы иметь такую ​​возможность динамически подключать бин в список или на карту (да, они у нас уже есть) ….

Ну, это было описание общей идеи. На днях я опубликую более подробную информацию об этой технологии, а также предоставлю полный исходный код для нее — так что следите за обновлениями!

ОБНОВИТЬ:

Я добавил еще одну запись в свой блог, которая более подробно описывает эту проблему. И оттуда доступна библиотека Inject4Spring — она ​​обеспечивает поддержку концепций, которые я там описал.

Пожалуйста, используйте следующую ссылку, чтобы получить его:

Представляем Inject4Spring