Кто-нибудь пытался автоматизировать проводку различных beans в Spring -managed bean на основе условия? Напр. если выполнено какое-либо условие, введите класс A, иначе B? Я видел в одном из результатов поиска Google, что это возможно с помощью SpEL (Spring Язык выражения), но не удалось найти рабочий пример.
Как сделать условную автоматическую проводку в Spring?
Ответ 1
Существует несколько способов достижения этого. В основном это зависит от условий, которые вы хотите выполнить.
Factory bean
Вы можете реализовать простой factory bean, чтобы выполнить условную проводку. Такой factory bean может содержать сложную логику кондиционирования:
public MyBeanFactoryBean implements FactoryBean<MyBean> {
// Using app context instead of bean references so that the unused
// dependency can be left uninitialized if it is lazily initialized
@Autowired
private ApplicationContext applicationContext;
public MyBean getObject() {
MyBean myBean = new MyBean();
if (true /* some condition */) {
myBean.setDependency(applicationContext.getBean(DependencyX.class));
} else {
myBean.setDependency(applicationContext.getBean(DependencyY.class));
}
return myBean;
}
// Implementation of isSingleton => false and getObjectType
}
Может быть, немного лучше подойти, если вы используете factory bean для создания зависимости bean, если вы хотите иметь только один такой bean в контексте вашего приложения:
public MyDependencyFactoryBean implements FactoryBean<MyDependency> {
public MyDependency getObject() {
if (true /* some condition */) {
return new MyDependencyX();
} else {
return new MyDependencyY();
}
}
// Implementation of isSingleton => false and getObjectType
}
SPEL
С SpEL существует много возможностей. Наиболее распространенными являются условия системного свойства:
<bean class="com.example.MyBean">
<property name="dependency" value="#{systemProperties['foo'] == 'bar' ? dependencyX : dependencyY}" />
</bean>
Заполнитель свойств
У вас может быть свойство placeholder, разрешающее вашу ссылку bean. Имя зависимостей может быть частью конфигурации приложения.
<bean class="com.example.MyBean">
<property name="dependency" ref="${dependencyName}" />
</bean>
Spring профили
Обычно условие, которое вы хотите оценить, означает, что весь набор beans должен или не должен быть зарегистрирован. Для этого можно использовать профили Spring:
<!-- Default dependency which is referred by myBean -->
<bean id="dependency" class="com.example.DependencyX" />
<beans profile="myProfile">
<!-- Override `dependency` definition if myProfile is active -->
<bean id="dependency" class="com.example.DependencyY" />
</beans>
Другие методы могут пометить определение bean как lazy-init="true"
, но определение будет по-прежнему регистрироваться внутри контекста приложения (и сделать вашу жизнь сложнее при использовании безусловного автоустройства). Вы также можете использовать профили с @Component
на основе beans через аннотацию @Profile
.
Отметьте ApplicationContextInitialier
(или этот пример), чтобы узнать, как вы можете программно активировать профили (т.е. на основе вашего состояния).
Конфигурация Java
Вот почему конфигурация на основе Java настолько популярна, насколько вы можете:
@Bean
public MyBean myBean() {
MyBean myBean = new MyBean();
if (true /* some condition */) {
myBean.setDependency(dependencyX());
} else {
myBean.setDependency(dependencyY());
}
return myBean;
}
Конечно, вы можете использовать более или менее все методы настройки в конфигурации на основе java (через @Profile
, @Value
или @Qualifier
+ @Autowired
).
Почтовый процессор
Spring предлагает множество точек захвата и SPI, где вы можете участвовать в жизненном цикле контекста приложения. Этот раздел требует немного больше знаний о внутренних функциях Spring.
BeanFactoryPostProcessor
может считывать и изменять определения bean (например, это означает, что разрешение заполнителя ${}
реализовано таким образом).
BeanPostProcessor
может обрабатывать экземпляры bean. Можно проверить только что созданный bean и играть с ним (например, @Scheduled
обработка аннотации реализована таким образом).
MergedBeanDefinitionPostProcessor
является расширением почтового процессора bean и может изменять определение bean непосредственно перед его созданием (@Autowired
обработка аннотации реализована таким образом).
ОБНОВЛЕНИЕ октябрь 2015
-
Spring 4 добавлен новый метод, как сделать условную bean регистрацию через
@Conditional
аннотация. Это также стоит проверить. -
Конечно, существует множество других способов использования Spring Boot через его
@ConditionalOn*
. -
Также обратите внимание, что как
@Import
, так и@ComponentScan
(и их XML-копии) подвергаются разрешению свойств (т.е. вы можете использовать${}
).
Ответ 2
У меня был случай, когда мне нужно было вводить разные bean-компоненты в зависимости от свойства: "my.property". В моем случае это решение было успешным:
<property name="name" ref="#{ ${my.property:false}==true ? 'bean1' : 'bean2' }"/>
Мне нужно было добавить апострофы вокруг имен бинов, чтобы они работали.