Преднамеренно установив для параметра Spring bean значение null
Я использую Spring для ввода JMS-соединения factory в свое приложение Java. Поскольку этот factory требуется только в рабочей среде, но пока я не разрабатываю, я поместил определение bean в отдельный XML, который я включил в свой основной applicationContext.xml. В производственных средах этот дополнительный файл содержит регулярное определение bean. В моей локальной среде dev я бы хотел, чтобы этот bean был нулевым. Попытка просто удалить определение bean all-toghether явно вызвало ошибку, когда Spring столкнулся с идентификатором ссылки, который он не знал.
Поэтому я попытался создать factory bean, который просто вернул бы null. Если я это сделаю, Spring (2.5.x) жалуется на то, что factory возвратил нуль, хотя на основе API-интерфейса Spring API-интерфейса FactoryBean я ожидал, что это сработает (см. Spring API doc).
XML выглядит примерно так:
<bean id="jmsConnectionFactoryFactory" class="de.airlinesim.jms.NullJmsConnectionFactoryFactory" />
<bean id="jmsConnectionFactory" factory-bean="jmsConnectionFactoryFactory" factory-method="getObject"/>
Каким был бы "правильный" способ сделать это?
Ответы
Ответ 1
factory-bean
/factory-method
не работает с null
, но пользовательская реализация FactoryBean
отлично работает:
public class NullFactoryBean implements FactoryBean<Void> {
public Void getObject() throws Exception {
return null;
}
public Class<? extends Void> getObjectType() {
return null;
}
public boolean isSingleton() {
return true;
}
}
<bean id="jmsConnectionFactory" class = "com.sample.NullFactoryBean" />
Ответ 2
Я уверен, что Spring не позволит вам связать null
с идентификатором бина или псевдонимом. Вы можете справиться с этим, установив свойства в null.
Вот как ты это сделал spring 2.5
<bean class="ExampleBean">
<property name="email"><null/></property>
</bean>
В Spring 3.0 вы также должны иметь возможность использовать язык выражений Spring (SpEL); например
<bean class="ExampleBean">
<property name="email" value="#{ null }"/>
</bean>
или любое выражение, которое вычисляется SPEL к null
.
И если вы используете конфигуратор-заполнитель, вы можете даже сделать это:
<bean class="ExampleBean">
<property name="email" value="#{ ${some.prop} }'"/>
</bean>
где some.prop
можно определить в файле свойств как:
some.prop=null
или же
some.prop=some.bean.id
Ответ 3
Для тех, кто подходит к этому вопросу, имейте в виду, что просто установка @Autowired аннотации как необязательной будет делать трюк (т.е. Spring оставит ссылочный нуль, если не найдено квалификационного bean).
@Autowired(required = false)
private SomeClass someBean
Обратите внимание, что вам нужно будет сделать это везде, на который ссылается bean, что может быть более сложным, чем создание null-factory, как упомянуто выше.
Ответ 4
Некоторые из отмеченных выше, ответ axtact не работает в контексте Autowiring, где Spring будет полагаться на правильную информацию из метода getObjectType(). Таким образом, вы можете столкнуться с такими ошибками, как:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [xxxxxxxxxxxxx] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true), @org.springframework.beans.factory.annotation.Qualifier(value=yyyyyyyyyyyyyyyy)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:920)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:789)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:703)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotatio
Итак, вот небольшая вариация, которая включает в себя предоставление пользователям возможности создавать объектный объект при построении. Использование свойства вместо конструктора-arg не сработало, потому что Spring не полностью инициализирует beans в этом контексте.
public class NullFactoryBean implements FactoryBean {
private final Class<?> objectType;
public NullFactoryBean(Class<?> objectType) {
this.objectType = objectType;
}
@Override
public Object getObject() throws Exception {
return null;
}
@Override
public Class<?> getObjectType() {
return objectType;
}
@Override
public boolean isSingleton() {
return false;
}
}
Ответ 5
В тестах null beans также может быть введено следующим образом:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = NullTest.class)
@Configuration
public class NullTest {
@Bean(name = "em")
public IEntityManager em() { return null; }
@Bean
public PlatformTransactionManager tm() { return null; }
@Resource
private SomeBean someBean; // this would get em and tm fields autowired to nulls
Ответ 6
Для всех, кто сталкивается с этим: другой подход, если вы используете Java 8, - это использовать функциональный интерфейс Supplier
для обертывания потенциально нулевого компонента:
@Bean
@Scope("singleton")
public Supplier<SomeBean> getSomeBean() {
SomeBean myBean = null; // or can set to a SomeBean instance
return () -> myBean;
}
При использовании @Autowired
конструктора @Autowired
это выглядит так:
private SomeBean someBean;
@Autowired
SomeService(Supplier<SomeBean> someBeanSupplier) {
this.someBean = someBeanSupplier.get();
}
Тогда поле someBean
в SomeService
может быть либо нулевым, либо ненулевым.
Ответ 7
Можете ли вы использовать специальный элемент <null>
bean? например.
<bean class="ExampleBean">
<property name="email"><null/></property>
</bean>
from документ, раздел 3.3.2.5