有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

JavaSpring3:注入默认Bean,除非存在另一个Bean

我想通过XML配置Spring,这样如果存在一个特定的bean,它就会被注入到目标bean中。如果不存在,将注入另一个默认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注入驱动程序。但是,如果我同时加载以下文件:

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

我希望使用customCarbean而不是defaultCarbean。我最初的尝试没有成功,但我认为这说明了我正在努力实现的目标:

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

我知道如何使用PropertyPlaceholderConfigurer实现这一点,但除了包含自定义bean的文件之外,我不想提供属性文件/VM property/environment variable/etc。谢谢


更新:

基于“使用工厂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,但这是可行的。也许添加一个定制的模式元素会让它更简洁

感谢您的补充意见


共 (4) 个答案

  1. # 1 楼答案

    使用JavaConfig:

    @Configuration
    public class CarConfig {
    
      @Autowired(required=false) @Qualifier("custom")
      Car customCar;
    
      @Autowired @Qualifier("default")
      Car defaultCar;
    
      @Bean
      public Car car() {
        return customCar != null ? customCar : defaultCar;
      }
    }  
    

    <bean id="defaultCar" class="Car">
      <qualifier="default"/>
      <property name="name" value="Honda Accord"/>
    </bean>
    
    <!-- customCar defined somewhere else -->
    
    <bean id="carDriver" class="Driver">
      <property name="car" ref="car"/>
    </bean> 
    
  2. # 3 楼答案

    在最新的Spring版本中,您可以使用基于SpEL的默认值定义:

    @Required
    @Value("#{new com.my.company.DefaultStrategy()}")
    public void setStrategy(final MyStrategy strategy) {
        this.strategy = strategy;
    }
    

    如果从Spring上下文设置此属性,则将注入在上下文中定义的bean。否则,容器将注入由@Value注释指定的bean

  3. # 4 楼答案

    我不确定,但是用primary="true"声明自定义bean可能会对您有所帮助