Преднамеренная установка боба Spring на ноль - PullRequest
30 голосов
/ 29 января 2010

Я использую Spring для внедрения фабрики соединений JMS в мое Java-приложение. Поскольку эта фабрика требуется только в производственной среде, а не во время разработки, я поместил определение bean-компонента в отдельный XML, который я включил в свой основной applicationContext.xml. В производственных средах этот дополнительный файл содержит определение обычного компонента. В моей локальной среде разработки я бы хотел, чтобы этот бин был нулевым. Попытка просто удалить все определение bean-компонента, очевидно, вызвала ошибку, когда Spring обнаружил ссылочный идентификатор, который он не знал.

Итак, я попытался создать фабричный бин, который бы просто возвращал ноль. Если я это сделаю, Spring (2.5.x) пожалуется, что фабрика вернула значение null, хотя на основании документа API Spring интерфейса FactoryBean я ожидал, что это сработает (см. Документация Spring API ).

XML выглядит примерно так:

<bean id="jmsConnectionFactoryFactory" class="de.airlinesim.jms.NullJmsConnectionFactoryFactory" />

<bean id="jmsConnectionFactory" factory-bean="jmsConnectionFactoryFactory" factory-method="getObject"/>

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

Ответы [ 7 ]

29 голосов
/ 29 января 2010

Я почти уверен, что Spring не позволит вам связать null с идентификатором компонента или псевдонимом. Вы можете справиться с этим, установив свойства в null.

Вот как вы это сделали весной 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
21 голосов
/ 29 января 2010

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" />
9 голосов
/ 21 октября 2014

Для всех, кто придет к этому вопросу, имейте в виду, что простая установка аннотации @Autowired в качестве необязательного сделает свое дело (т. Е. Spring оставит ссылку нулевой, если не найден соответствующий компонент).

@Autowired(required = false)
private SomeClass someBean

Обратите внимание, что вам придется делать это везде, на которые ссылается bean-компонент, что может быть более сложной задачей, чем создание нулевой фабрики, как упомянуто выше.

4 голосов
/ 28 ноября 2011

Некоторые отмеченные выше, ответ 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

Итак, вот небольшая вариация, которая включает в себя предоставление пользователям возможности принудительно указывать тип объекта при создании. Использование свойства вместо constructor-arg не сработало, потому что Spring не полностью инициализирует bean-компоненты в этом контексте.

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;
    }
}
0 голосов
/ 04 апреля 2019

Для всех, кто сталкивался с этим: другой подход, если вы используете Java 8, - это использовать функциональный интерфейс Supplier для упаковки потенциально нулевого компонента:

@Bean
@Scope("singleton")
public Supplier<SomeBean> getSomeBean() {
  SomeBean myBean = null;  // or can set to a SomeBean instance
  return () -> myBean;
}

При использовании инжектора конструктора @Autowired это выглядит следующим образом:

private SomeBean someBean;

@Autowired
SomeService(Supplier<SomeBean> someBeanSupplier) {
    this.someBean = someBeanSupplier.get();
}

Тогда поле someBean в SomeService может быть либо нулевым, либо ненулевым.

0 голосов
/ 28 июня 2017

В тестах также можно вводить нулевые бины так:

@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
0 голосов
/ 29 января 2010

Можете ли вы использовать специальный элемент <null> bean? например,

<bean class="ExampleBean">
<property name="email"><null/></property>
</bean>

от Документ , раздел 3.3.2.5

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...