web-dev-qa-db-ja.com

XMLを使用せずにSpringでプロパティに基づいて実行時に異なるサービスを注入する方法

JavaスタンドアロンアプリケーションにSpring Bootを使用しています。サービスを利用するBeanがあります。プロパティファイルのプロパティに基づいて、実行時にそのサービスのさまざまな実装を注入したいです。 Springで(その点で4つ)。


これはFactoryパターンのように聞こえますが、Springではこのように注釈を使用して問題を解決することもできます。

_@Autowired @Qualifier("selectorProperty") private MyService myService;
_

次に、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
_

一方、ファクトリパターンに関しては、SpringではServiceLocatorFactoryBeanを使用して、同じ機能を提供するファクトリを作成できます。

_<bean
  class="org.springframework.beans.factory.config.ServiceLocatorFactoryBean"
  id="myServiceFactory">
  <property
    name="serviceLocatorInterface"
    value="my.company.MyServiceFactory">
  </property>
</bean>

public interface MyServiceFactory
{
    MyService getMyService(String selector);
}
_

そして、Beanでこのようなものを使用して、プロパティの値に応じて実行時に適切な実装を取得できます。

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

@Autowired private MyServiceFactory myServiceFactory;

private MyService myService;

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

しかし、このソリューションの問題は、XMLを使用してファクトリーを定義することを避ける方法を見つけることができず、注釈のみを使用したいことです。


だから質問は、アノテーションのみを使用してServiceLocatorFactoryBean(または同等のもの)を使用する方法がありますか、またはXMLでBeanを定義したくない場合は@Autowired @Qualifier方法を使用することを強制されますか?または、Spring 4でXMLを回避して、プロパティに基づいて実行時に異なるサービスを注入する他の方法はありますか?エイリアスで_@Autowired @Qualifier_を使用するだけの場合、よく知られているファクトリパターンを使用するよりも優れている理由を教えてください。

余分なXMLを使用すると、Launcherクラスで@ImportResource("classpath:beans.xml")を使用せざるを得なくなり、どちらも使用しません。

ありがとう。

18
Pedro Lopez

実際、XMLなしでServiceLocatorFactoryを使用するには、構成ファイルでBeanとして宣言します。

@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);
}
9
Pedro Lopez

Springプロファイルを使用しています

たとえば、dataSourcesを使用すると、好きなだけdataSourcesを定義できます

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

1つまたは別の構成をアクティブにします(それらはすべてメイン構成にインポートする必要があり、アクティブなプロファイルに基づいて無視されます)。

ここに良い記事があります: http://spring.io/blog/2011/02/14/spring-3-1-m1-introducing-profile/

8
mavarazy