java - Spring 3 : Inject Default Bean Unless Another Bean Present

标签 java xml spring spring-el

我想通过 XML 配置 Spring,如果存在特定的 bean,它将被注入(inject)目标 bean。如果它不存在,将注入(inject)一个不同的默认 bean。

例如,如果我有这样的文件

<bean id="carDriver" class="Driver">
  <property name="car" value="SOME EXPRESSION GOES HERE, SEE ATTEMPT BELOW"/>
</bean>

<bead id="defaultCar" class="Car">
  <property name="name" value="Honda Accord"/>
</bean>

并加载它,我希望将 defaultCar 注入(inject)驱动程序。但是,如果我还加载以下文件:

<bean id="customCar" class="FlyingCar">
  <property name="name" value="Rocket Car"/>
  <property name="maxAltitude" value="80000"/>
</bean>

我希望使用 customCar bean 而不是 defaultCar bean。我最初的尝试不起作用,但我认为说明了我想要实现的目标:

<bean id="carDriver" class="Driver">
  <property name="car" value="#{ @customCar eq null ? 'defaultCar' : 'customCar' }"/>
</bean>

我知道如何使用 PropertyPlaceholderConfigurer 来做到这一点,但我不想除了包含自定义 bean 。谢谢!


更新:

基于“使用工厂 bean”的评论,我对此进行了调查并提出了以下解决方案。首先,我创建了一个通用工厂 bean,它允许您指定默认 bean 名称和覆盖 bean 名称:

public class DefaultOverrideFactoryBean implements FactoryBean, BeanFactoryAware {

    public Object getObject() throws Exception {
        return beanFactory.containsBean(overrideBeanName) ?
               beanFactory.getBean(overrideBeanName)      :
               beanFactory.getBean(defaultBeanName);
    }

    public Class<?> getObjectType() {
        return Object.class;
    }

    public boolean isSingleton() {
        return true;
    }

    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

    public void setDefaultBeanName(String defaultBeanName) {
        this.defaultBeanName = defaultBeanName;
    }

    public void setOverrideBeanName(String overrideBeanName) {
        this.overrideBeanName = overrideBeanName;
    }

    private String defaultBeanName;
    private String overrideBeanName;
    private BeanFactory beanFactory;
}

要配置我的示例汽车司机,您可以这样做:

<bean id="carDriver" class="Driver">
  <property name="car">
    <bean class="DefaultOverrideFactoryBean">
      <property name="defaultBeanName" value="defaultCar"/>
      <property name="overrideBeanName" value="customCar"/>
    </bean>
  </property>
</bean>

我更喜欢使用 SpEL,但这很有效。或许添加一个自定义架构元素会更简洁。

欢迎补充评论。

最佳答案

您可以使用@Qualifier 选择一个版本的 Car(自定义或默认),但您应该知道您要使用的具体名称,并且您可能只想使用:

 @Autowired
 private Car car;

您也可以使用@Primary 来解决这个问题,但它只是提供了一个避免歧义的偏好,并且会创建不需要的版本。 所以我建议使用注释

org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean

因此,如果没有创建另一个 bean,您只会实例化一个 bean。当 bean 在不同的模块中声明时,它特别有用。

//Core module creates a default Car
@Bean()
@ConditionalOnMissingBean(Car.class)
Car car()
{
  return new DefaultCar();
}

//Car module creates the wanted prototype car
@Bean()
Car car()
{
  return new Toyota();
}

关于java - Spring 3 : Inject Default Bean Unless Another Bean Present,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5466462/

相关文章:

java - mysql 时间戳的 Joda-Time 日期格式中的当前日期时间

java - 单击另一个按钮即可交换 2 个按钮上的图像

java - 使用泛型和 rxjava 的不兼容类型

java - Selenium Java 如何在测试步骤失败时保持浏览器窗口打开

java - Spring XML 模式中的错误 "No setter found for property ' oAuth2RequestValidator'"

javascript - 使用 .contents() 获取 jquery 中 xml 节点的内容

android - Android 中的 Spring restclient 通过 HTTP GET 检索 XML 数据

java - Maven 依赖项失败并出现 501 错误

java - 需要帮助将链接列表实现到 TableView javaFX 并将其保存到文件中

java - 在不同环境下构建spring boot jar失败