Spring Boot + Domaで動的データソース切り替えを実現する

Spring Boot + Domaでjsonを返すRESTサーバを作ってみました。

マルチテナントアプリという要件があったので、データソースを動的に切り替えられるようにしています。

以前試した CDIで複数データソースの切り替え のSpring + Doma版です。

 

データソースを動的に切り替えるためのポイントは以下になります。

 

@ComponentScanアノテーションのscopeResolverでJsr330ScopeMetadataResolverを指定し、スコープをPrototypeにする

{% codeblock %} @EnableAutoConfiguration @ComponentScan(basePackages = “info.matsumana”, scopeResolver = Jsr330ScopeMetadataResolver.class) public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } {% endcodeblock %}

 

AbstractRoutingDataSourceを継承したクラスを作り(サンプルソースではDynamicRoutingDataSourceResolver)、
determineCurrentLookupKeyメソッドでデータソース名をreturnする
このサンプルソースではシステム時刻でデータソースを切り替えていますが、実際はHTTPヘッダーやCookieで切り替える事になると思います

{% codeblock %} public class DynamicRoutingDataSourceResolver extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { // システム時刻が偶数秒ならdataSource1に接続する DateTime dt = new DateTime(); int sec = Integer.parseInt(dt.toString(“s”)); if (sec % 2 == 0) { return “dataSource1”; } else { return “dataSource2”; } } } {% endcodeblock %}

 

AppConfigにデータソースを複数定義しておき(サンプルソースではdataSource1とdataSource2)、
DynamicRoutingDataSourceResolverでラップしてreturnするメソッドをDataSouceとして使用する

{% codeblock %} @Configuration public class AppConfig {

@Bean()
public DataSource dataSource1() {
    org.apache.tomcat.jdbc.pool.DataSource ds = new org.apache.tomcat.jdbc.pool.DataSource();
    ds.setDriverClassName("org.postgresql.Driver");
    ds.setUrl("jdbc:postgresql://localhost:5432/db1");
    ds.setUsername("postgres");
    ds.setDefaultAutoCommit(false);

    return ds;
}

@Bean()
public DataSource dataSource2() {
    org.apache.tomcat.jdbc.pool.DataSource ds = new org.apache.tomcat.jdbc.pool.DataSource();
    ds.setDriverClassName("org.postgresql.Driver");
    ds.setUrl("jdbc:postgresql://localhost:5432/db2");
    ds.setUsername("postgres");
    ds.setDefaultAutoCommit(false);

    return ds;
}

@Bean()
public DynamicRoutingDataSourceResolver dataSource() {
    DynamicRoutingDataSourceResolver resolver = new DynamicRoutingDataSourceResolver();

    Map<Object, Object> dataSources = Maps.newHashMap();
    dataSources.put("dataSource1", dataSource1());
    dataSources.put("dataSource2", dataSource2());

    resolver.setTargetDataSources(dataSources);

    return resolver;
}

} {% endcodeblock %}

 

これで各コンポーネントが毎回インスタンス化され、
DynamicRoutingDataSourceResolver#determineCurrentLookupKey()が毎回呼ばれるようになります。

Provider<T>を使っても実現できる気がする。

ソースは ここ に置いてます。

 

参考にしたページ

 
comments powered by Disqus