2014-10-20 4 views
16

Java 독립 실행 형 응용 프로그램 용 Spring Boot를 사용하고 있습니다. 나는 서비스를 이용하는 콩을 가지고있다. 나는 Spring에서 프로퍼티 파일의 프로퍼티를 기반으로 런타임에 해당 서비스의 다른 구현을 삽입하려고한다.XML없이 Spring을 사용하여 속성을 기반으로 런타임에 다른 서비스를 주입하는 방법


이것은 공장 패턴과 비슷하지만, 스프링은 주석을 사용하여 문제를 해결할 수 있습니다.

beans.xml 파일에 별칭이 있으므로 @Qualifier의 속성을 사용할 수 있습니다.

<alias name="${selector.property}" alias="selectorProperty" /> 

다른 구현에서는 다른 한정자가 있습니다.

@Component("Selector1") 
public class MyServiceImpl1 

@Component("Selector2") 
public class MyServiceImpl2 

application.properties

selector.property = Selector1 

selector.property = Selector2 

공장 패턴에 대한 반면, 봄에 당신은 당신에게 동일한 기능을 제공 할 공장을 만들 ServiceLocatorFactoryBean를 사용할 수 있습니다.

그리고 나서 당신의 빈에서 당신은 속성의 값에 따라 런타임에 올바른 구현을 얻기 위해 이와 같은 것을 사용할 수 있습니다.

@Value("${selector.property}") private String selectorProperty; 

@Autowired private MyServiceFactory myServiceFactory; 

private MyService myService; 

@PostConstruct 
public void postConstruct() 
{ 
    this.myService = myServiceFactory.getMyService(selectorProperty); 
} 

는 그러나이 솔루션의 문제는 내가 공장을 정의하기 위해 XML을 사용하지 않도록 할 수있는 방법을 찾을 수 없습니다, 그리고 난 단지 주석을 사용하고자하는 것입니다.


그래서 질문은, 단지 주석을 사용하여 ServiceLocatorFactoryBean (또는 이에 해당하는)를 사용하는 방법이 될 또는 나는 콩을 정의하지 않으려면 @Autowired @Qualifier 방법을 사용하도록 강요 오전 것 XML로? 아니면 XML을 피하는 Spring 4의 속성을 기반으로 런타임에 다른 서비스를 주입하는 다른 방법이 있습니까? 귀하의 대답이 별칭과 함께 @Autowired @Qualifier을 사용하는 경우 잘 알려진 공장 패턴을 사용하는 것보다 더 나은 이유를 제시하십시오.

여분의 XML을 사용하면 Launcher 클래스에서 @ImportResource("classpath:beans.xml")을 사용하게됩니다. 사용하지 않으려합니다.

감사합니다. 나는 봄 사용하고

+0

@Qualifier ("$ {selector.property}")를 시도하셨습니까? 콩을 동적으로 이름 짓는 것이 가능합니다. 그래서이 방법으로 한정자를 설정할 수도 있습니다 ... 시도해 보지 않았습니다. – Nadir

+0

시도했지만 작동하지 않습니다. @Autowired @Qualifier ("$ {selector.property}")는 null로 해석됩니다. 별칭은 중간 단계로 필요합니다. 어쨌든 제안 해 주셔서 감사합니다. –

+0

잘 모르겠다면, 아카이브로 무엇을 하려는지, 프로필을 가지고 스프링 구성을 분리 해 보았습니까? – mavarazy

답변

8

사실, 당신이 당신의 구성 파일에서 빈으로 선언하여 XML없이 ServiceLocatorFactory를 사용할 수 있습니다

는 여기에 좋은 기사입니다.

@Bean 
public ServiceLocatorFactoryBean myFactoryServiceLocatorFactoryBean() 
{ 
    ServiceLocatorFactoryBean bean = new ServiceLocatorFactoryBean(); 
    bean.setServiceLocatorInterface(MyServiceFactory.class); 
    return bean; 
} 

@Bean 
public MyServiceFactory myServiceFactory() 
{ 
    return (MyServiceFactory) myFactoryServiceLocatorFactoryBean().getObject(); 
} 

그렇다면 평소처럼 공장을 사용할 수는 있지만 XML은 관련이 없습니다.

@Value("${selector.property}") private String selectorProperty; 

@Autowired @Qualifier("myServiceFactory") private MyServiceFactory myServiceFactory; 

private MyService myService; 

@PostConstruct 
public void postConstruct() 
{ 
    this.myService = myServiceFactory.getMyService(selectorProperty); 
} 
+0

한정자없이'MyServiceFactory'를 Autowiring하면 추가로'myServiceFactory()'를 추가하지 않아도 작동합니다. 이 경우에는 함수 이름과 한정어 이름이 관련되어 있는지 의심 스럽습니다. 하지만 그렇습니다. 전반적으로 솔루션이 좋습니다. – Lokesh

7

를 지정하여, 당신은

@Configuration 
@Profile("dev") 
public class StandaloneDataConfig { 

    @Bean 
    public DataSource dataSource() { 
     return new EmbeddedDatabaseBuilder() 
      .setType(EmbeddedDatabaseType.HSQL) 
      .addScript("classpath:com/bank/config/sql/schema.sql") 
      .addScript("classpath:com/bank/config/sql/test-data.sql") 
      .build(); 
    } 

} 

@Configuration 
@Profile("cloud") 
public class CloudDataConfig { 

    @Bean 
    public DataSource dataSource() { 
     return new EmbeddedDatabaseBuilder() 
      .setType(EmbeddedDatabaseType.HSQL) 
      .addScript("classpath:com/bank/config/sql/schema.sql") 
      .addScript("classpath:com/bank/config/sql/test-data.sql") 
      .build(); 
    } 

} 

그리고 런타임에서

을 원하는대로 당신은 많은 데이터 소스를 정의 할 수 있습니다를 사용하여 데이터 소스 와 예를 들어

프로필 -Dspring.profiles.active = "myProfile"

당신은 하나 또는 다른 구성을 활성화합니다 (모두 기본 구성에 가져와야하며 활성화 된 프로파일을 기준으로 무시됩니다). http://spring.io/blog/2011/02/14/spring-3-1-m1-introducing-profile/

+0

나는이 해결책을 좋아한다. 이 특별한 경우에는 다른 프로파일이 없습니다. 이런 식으로 사용할 수는 있지만 인터페이스를 구현할 때마다 다른 프로필이 필요합니다. 두 개의 공장이 있다면 그것은 지저분 해집니다. 어쨌든 답장을 보내 주셔서 감사합니다. –

+0

당신은 환영합니다 :) – mavarazy

관련 문제