привязка к весенним бобам с курицей и яйцом

#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 в конструкторе.