#java #spring #inversion-of-control
#java #весна #инверсия контроля
Вопрос:
Хорошо, итак, вот мой вариант использования:
У меня есть следующие классы, каждый из которых инкапсулирует экземпляр следующего в строке. Итак:
A -> B -> C -> D
например: в классе A у меня есть экземпляр класса B, а в классе B у меня есть экземпляр C и так далее.
Ну, я пытаюсь преобразовать логику загрузки инициализации внедрения в гибридную систему Spring. Общая идея заключается в том, что B, C и D должны быть более или менее ApplicationContextAware
. Под этим я подразумеваю, что они фактически не будут реализовывать этот интерфейс, но вместо этого потребуют ApplicationContext
в качестве параметра конструктора. Таким образом, в гибридном подходе (где разработчик не использует Spring для инициализации экземпляра) они должны, по крайней мере, передавать ApplicationContext
, чтобы можно было подключить дополнительные компоненты. Проблема в том, что для того, чтобы контейнер Spring загрузил компоненты, я теперь должен передать ApplicationContext
в XML. Но, насколько я могу судить, хорошего способа сделать это нет.
Я пробовал что-то вроде этого:
public class ApplicationContextPlaceholder implements ApplicationContextAware {
private ApplicationContext _applicationContext;
public void setApplicationContext( final ApplicationContext applicationContext ) throws BeansException {
_applicationContext = applicationContext;
}
public ApplicationContext getApplicationContext() {
return _applicationContext;
}
}
<bean id="a" class="com.company.A">
<constructor-arg>
<bean id="applicationContext" class="com.company.ApplicationContextPlaceholder" />
</constructor-arg>
</bean>
Но, очевидно, это не имеет никакого смысла, поскольку ApplicationContextPlaceholder
на самом деле это не ApplicationContext
an. Я также искал способы ссылаться на контекст внутри XML, но ничего не нахожу.
Кто-нибудь знает элегантное решение проблемы такого типа?
ПРАВКА # 1:
Я думал об этом, и я мог бы ApplicationContextPlaceholder
также реализовать ApplicationContext
и просто делегировать введенный контекст, а затем мне пришло в голову, что, возможно, просто, возможно, это было уже весной…но, насколько я могу судить, нет.
ПРАВКА # 2:
Причина, по которой каждому классу нужен ApplicationContext
, заключается в том, что если разработчик хочет переопределить один из классов в цепочке (скажем, C для аргументации). В этом случае дочернему классу C все равно нужно будет загружать D через Spring.
Комментарии:
1. Вам обязательно нужно
ApplicationContext
в вашем конструкторе? Вы должны иметь возможность просто автоматически подключить его, если вы этого не сделаете.2. Да, для каждого экземпляра требуется
ApplicationContext
.3. Было бы полезно, если бы вы могли объяснить намерение, стоящее за наличием такого количества классов тяжелого веса (т. Е., по сути, являющихся ApplicationContextAware) подряд
4. @DanielDinnies — Я отредактирую это, чтобы заполнить то, что вы просили.
Ответ №1:
Если класс не предоставляет дополнительную функциональность подключения, вам следует избегать раскрытия ApplicationContext
. Цитирую ссылку на Spring: in general you should avoid it, because it couples the code to Spring and does not follow the Inversion of Control style
.
Если вы предоставляете дополнительную функциональность (возможно, например, фабричный класс, который использует ApplicationContext
для сборки объектов), то разумно реализовать ApplicationContextAware
, поскольку ваша функциональность уже привязана к Spring.
Если вы рассмотрели свои альтернативы внедрения зависимостей и решили внедрить ApplicationContext
в свои компоненты, ваш ApplicationContextPlaceholder
класс (я бы держался подальше от Placeholder
префикса, чтобы избежать путаницы с заполнителями свойств Spring), безусловно, является решением. (Поскольку это ваш собственный класс, почему бы не расширить ApplicationObjectSupport
для дополнительной функциональности.)
Этот класс необходимо будет определить и инициализировать в вашей конфигурации, например:
<bean id="appCtxHolder" class="ApplicationContextHolder" />
Поскольку ApplicationContextHolder
реализует ApplicationContextAware
, Spring будет вводить ApplicationContext
в appCtxHolder
при инициализации. Вы можете использовать это для внедрения конструктора, например:
<bean id="a" class="com.company.A">
<constructor-arg>
<bean factory-bean="appCtxHolder" factory-method="getApplicationContext" />
</constructor-arg>
</bean>
Комментарии:
1. Об этом есть над чем подумать, спасибо за информацию 1. Я действительно думаю, что мне нужен контекст до конца в каждом классе in. Я понимаю, что это создает тесную связь с Spring, однако этот конкретный проект представляет собой объединение Spring и нашей бизнес-логики, поэтому, учитывая, что это может быть нормально. Я взвеслю свои варианты и проверю еще раз, пока что это самый близкий ответ, который я должен принять. Спасибо!
Ответ №2:
ApplicationContextPlaceholder
все могло бы быть статичным. В этом случае вам не нужно переходить ApplicationContext
по кругу, когда API запрашивает определенный компонент, вы можете проверить, является ли он null, и если это так, загрузите его, используя ApplicationContext
from ApplicationContextPlaceholder
. Это предполагает внедрение на основе установщика, если вы делаете это на основе конструктора, вы также можете инициализировать beans в конструкторе.