У нас есть большое приложение на основе Spring, которое включает в себя различные модули, а также настраиваемые API. Хотя есть модули, которым нужен контекст Spring, поскольку они просто обертывают части модели предметной области, мы думаем, что некоторые из наших API этого не делают.
Например, мы написали оболочку для Джексона/Джерси, чтобы предоставлять и использовать службы REST. Существует центральный интерфейс для доступа к этому API. Однако для реализации нужен другой класс, а тот другой и так далее. Таким образом, простая инициализация будет
A a = new A(new B(new C(), new D(new E())))
Что мы в настоящее время спасены от использования @Inject
. Контекст для этого API сканирует пакет, а затем импортируется в целевое приложение.
<import resource="classpath:api-context.xml" />
Нам это не очень удобно, и мы хотим выкинуть контекст Spring из оболочки REST, то есть мы хотим, чтобы API не требовал его, но не знаем, как это сделать. Это должно означать одно из следующих двух:
аргументы конструктора
В целевом контексте это потребует создания нескольких bean-компонентов, каждый из которых инициализируется своими зависимостями.
<bean id="a" class="...A">
<constructor-arg>
<ref = b " />
</constructor-arg>
</bean>
<bean id="b" class="...B">
<constructor-arg>
<ref = c " />
</constructor-arg>
</bean>
<!-- And so on -->
Геттеры и сеттеры
Или, предполагая, что A
является конкретной реализацией AInterface
, а AInterface является центральным доступом, мы могли бы просто сказать, что A использует определенную реализацию BInterface по умолчанию и так далее, и фактически устанавливает их внутри с помощью new:
public class A implements AInterface {
private BInterface b = new B();
public getB() {return b;}
public setB(B b) {this.b = b) }
}
// and so on
Затем в моем целевом контексте я могу инициализировать центральный доступ одной строкой, если хочу использовать конфигурацию по умолчанию.
<bean id="a" class="...A" />
или использовать свойства, чтобы установить его B. Однако, если я хочу изменить что-то дальше по линии, мне придется инициализировать все bean-компоненты и установить свойства.
Также мне не кажется чистым, если я использую new для службы вне моих тестов.
Поэтому нам интересно, как другие разработчики API делают свои интерфейсы и bean-компоненты доступными, не полагаясь на импорт контекста (который, кстати, также загромождает целевой контекст множеством потенциально ненужных bean-компонентов, например, если API предоставляет несколько сервисов, а я хочу только использовать один)?
изменить
Не уверен, что что-то из этого лучше:
public class A implements AInterface {
private BInterface b
public A() {
b = new B();
}
public getB() {return b;}
public setB(B b) {this.b = b) }
}
or
public class A implements AInterface {
private BInterface b
public A(B b) {
this.b = b;
}
}
Последнее кажется лучшим с точки зрения тестирования, но оно возвращает нас к цепочке, описанной выше, где мне придется инициализировать все зависимые компоненты в моем контексте, прежде чем я смогу инициализировать A. Это кажется слишком большим накладным расходом на настройку.
Кто-то может возразить, что это вполне нормально, что все зависимости должны быть инициализированы перед использованием класса и что мы должны реорганизовать наш код. Однако тогда мы получим множество служебных/вспомогательных классов, которые также не являются лучшим дизайном, поскольку их трудно заменить или протестировать.
@Configuration
, и указать ссылки между bean-компонентами в этой конфигурации или с помощью @Autowired или эквивалентного. - person EngineerBetter_DJ   schedule 05.07.2012