Подтвердить что ты не робот

Преднамеренно установив для параметра 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"/>

Каким был бы "правильный" способ сделать это?

4b9b3361

Ответ 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