2011-03-29 2 views
12

저는 특정 빈이 존재하면 목표 빈에 주입 할 수 있도록 XML을 통해 Spring을 설정하고 싶습니다. 존재하지 않으면 다른 기본 빈이 삽입됩니다. 예를 들어스프링 3 : 다른 콩이없는 한 기본 빈을 넣으십시오.

나는이

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

나는 customCar 콩 대신 defaultCar 콩의 사용하고자하는 것입니다. 내 초기 시도가 작동하지 않습니다,하지만 난 달성하기 위해 노력하고있어 설명 생각 : 나는 PropertyPlaceholderConfigurer이 작업을 수행하는 방법을 알고

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

,하지만 난하지 않으려는 속성 파일을 제공해야합니다/VM 프로퍼티/환경 변수 등을 포함 할 수있다. 감사!


는 업데이트 : "공장 콩을 사용하여"의견을 바탕으로

, 나는이 들여다 다음과 같은 솔루션을 함께했다. 첫째, 난 당신이 기본 빈 이름과 재정의 콩 이름을 지정할 수있는 일반 공장 콩 만든 :

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> 

I을 SpEL을 사용하는 것이 더 좋았지 만 이것이 효과적입니다. 아마도 사용자 정의 스키마 요소를 추가하면이 클리너가 만들어집니다.

추가 의견 감사합니다.

+1

FactoryCar bean을 생성하지 않는 이유는 무엇입니까? 그런 다음 carDriver 내의 해당 팩토리를 참조하십시오. – chris

답변

5

사용 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> 
1

SpEL을 기반 정의 와이 우리의 기본값 :

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

이 속성을 Spring 컨텍스트에서 설정하면 컨텍스트에서 정의한 bean이 삽입됩니다. 그렇지 않은 경우, 컨테이너는 @Value 주석으로 지정된 bean을 삽입합니다.

3

잘 모르겠지만 아마 primary="true"으로 사용자 정의 빈을 선언하면 도움이 될 것입니다.

+0

Primary = true는이 유스 케이스에 대한 길입니다. – Rolf

7

스프링 3.0.7

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

나를 위해 다음 SpEL을 수행해야했습니다. # {getBeanFactory(). containsBean ('customCar')? customCar : defaultCar}' – Blaine

6

당신은 자동차 (사용자 정의 또는 기본) 한 버전을 선택하는 @Qualifier를 사용 할 수 있습니다,하지만 당신은 무엇을 거 사용의 특정 이름을 알게 될 것이다, 그리고 당신은 그냥 사용할 수 있습니다 :

@Autowired 
private Car car; 

이 문제를 해결하기 위해 @Primary를 사용할 수도 있지만 모호성을 피하기 위해 환경 설정을 제공하므로 원하지 않는 버전이 만들어집니다. 그래서 내가 다른이 생성되지 않은 경우 그래서 당신은 하나의 빈을 instantate 것이다 주석

org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean 

를 사용하는 권 해드립니다 것이다. bean이 differents 모듈에서 선언 될 때 특별히 유용합니다. 이 같이 할 수

//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(); 
} 
+1

@ConditionalOnMissingBean은 스프링 부트를 사용할 때만 작동합니다. – Xdg

0

스프링 부팅 스타터 1.4.0.RELEASE (봄 코어 4.3.2.RELEASE)
나 :

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

} 
관련 문제