Spring 3: Inject Default Bean Unless Another Bean Present

依然范特西╮ 提交于 2019-12-02 22:59:26

You may used @Qualifier to choose one version of Car (custom or default), but you shall know the specific name of what you gonna use, and you may want to use just:

 @Autowired
 private Car car;

You may also use @Primary to solve this, but it just gives a preference to avoid ambiguity and it will be created the unwanted versions. So i would recomend to use the annotation

org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean

So you will only instantate one bean if another is not created. Its specially usefull when the beans are declared in differents modules.

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

and

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

With Spring 3.0.7

<bean id="carDriver" class="Driver">
   <property name="car" value="#{ getBeanFactory().containsBean('customCar') ? getBeanFactory().getBean('customCar') : defaultCar }"/>
</bean>

Use 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;
  }
}  

and

<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> 

I'm not sure but probably declaring custom bean with primary="true" might help you.

With the newest Spring version you can use SpEL-based definition of your default value:

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

If you set this property from Spring context, bean that you defined in context will be injected. Otherwise, container injects bean specified by @Value annotation.

spring-boot-starter 1.4.0.RELEASE (spring-core 4.3.2.RELEASE)
or you could do like this:

public interface SomeService {
}
------------------------------------------------------------------------    
public interface CustomSomeService extends SomeService {
}
------------------------------------------------------------------------    
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.stereotype.Service;

@Service
@ConditionalOnMissingBean(CustomSomeService.class)
public class DefaultSomeService implements SomeService {
}
------------------------------------------------------------------------    
import org.springframework.stereotype.Service;

@Service
public class AdvancedSomeService implements CustomSomeService {
}
------------------------------------------------------------------------

class Application{

@Autowired
private SomeService someService;
/*
 Now if ApplicationContext contains CustomSomeService implementation 
'someService' use custom implementation. If CustomSomeService is 
missing 'someService' contains DefaultSomeService implementation.
*/
}
------------------------------------------------------------------------

import static org.junit.Assert.assertTrue;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@ContextConfiguration(classes = { DefaultSomeService.class, AdvancedSomeService.class })
public class SomeServiceTest {

    @Autowired
    private SomeService someService;

    @Test
    public void test() {
        assertTrue(AdvancedSomeService.class.isInstance(someService));
    }

}

------------------------------------------------------------------------

import static org.junit.Assert.assertTrue;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@ContextConfiguration(classes = { DefaultSomeService.class})
public class SomeServiceTest {

    @Autowired
    private SomeService someService;

    @Test
    public void test() {
        assertTrue(DefaultSomeService.class.isInstance(someService));
    }

}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!