[Spring]Doma2で複数データソース設定

## やること
内部DBだけでなく、外部DBにも接続したいよーってときありますよね
SpringBootとDoma2で複数データソースに接続していきます

## 環境
Java 11
Spring Boot 2.6.1
Doma 2.50.0
MySQL 8.0.25
Gradle 2.24

## 実装

### データベース接続設定

```application.properties
# DB1
datasource.one.jdbcUrl=jdbc:mysql://sample1.com:3306/sample1?autoReconnect=true&useSSL=false
datasource.one.username=sample
datasource.one.password=sample
# DB2
datasource.two.jdbcUrl=jdbc:mysql://sample2.com:3306/sample2?autoReconnect=true&useSSL=false
datasource.two.username=sample
datasource.two.password=sample
```

データベースへの接続はHikariCPを利用します。
接続するURLは、`jdbcUrl`または、`jdbc-url`で設定する必要があります。
`url`で設定すると、下記エラーで怒られます。

```
Caused by: java.lang.IllegalArgumentException: jdbcUrl is required with driverClassName.
```

### Applicationクラス
Spring Bootでは、単一データソースを前提とする動作になるため、
`exclude = {DataSourceAutoConfiguration.class}` で自動設定を無効にします。

```SampleApplication.java
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class SampleApplication {
	public static void main(String[] args) {
		SpringApplication.run(SampleApplication.class, args);
	}

}
```

### Configクラス
Doma2を利用するため、Configクラスを実装します
設定ファイルから取得した接続情報を保持するため、HikariConfigクラスを継承しています
また、同じタイプのBeanが複数作成されるため、片方のConfigクラスに`@Primary`を付与することで、SpringにBeanの優先度を伝えてあげます

```DataSourceOneConfig.java
@Configuration("dataSourceOneConfig")
@ConfigurationProperties("datasource.one")
@Primary
public class DataSourceOneConfig extends HikariConfig implements Config {
    private DataSource dataSource;

    @PostConstruct
    public void postConstruct() {
        this.dataSource = new TransactionAwareDataSourceProxy(new HikariDataSource(this));
    }

    @Override
    public Dialect getDialect() {
        return new MysqlDialect();
    }

    @Override
    public DataSource getDataSource() {
        return this.dataSource;
    }
}
```

```DataSourceTwoConfig.java
@Configuration("dataSourceTwoConfig")
@ConfigurationProperties("datasource.two")
public class DataSourceTwoConfig extends HikariConfig implements Config {
    private DataSource dataSource;

    @PostConstruct
    public void postConstruct() {
        this.dataSource = new TransactionAwareDataSourceProxy(new HikariDataSource(this));
    }

    @Override
    public Dialect getDialect() {
        return new MysqlDialect();
    }

    @Override
    public DataSource getDataSource() {
        return this.dataSource;
    }
}
```

### Daoを作成
`@AnnotateWith`でDaoインターフェースの実装クラスにアノテーションを付与していきます
`@ConfigAutowireable`で`@Repository`と`@Autowired`を付与しようとすると怒られます


```SampleOneDao.java
@Dao
@AnnotateWith(annotations = {
        @Annotation(target = AnnotationTarget.CLASS, type = Repository.class),
        @Annotation(target = AnnotationTarget.CLASS, type = Component.class),
        @Annotation(target = AnnotationTarget.CONSTRUCTOR, type = Autowired.class),
        @Annotation(target = AnnotationTarget.CONSTRUCTOR_PARAMETER, type = Qualifier.class, elements = "\"dataSourceOneConfig\"")
})
public interface SampleOneDao {

}
```

```SampleTwoDao.java
@Dao
@AnnotateWith(annotations = {

        @Annotation(target = AnnotationTarget.CLASS, type = Repository.class),
        @Annotation(target = AnnotationTarget.CLASS, type = Component.class),
        @Annotation(target = AnnotationTarget.CONSTRUCTOR, type = Autowired.class),
        @Annotation(target = AnnotationTarget.CONSTRUCTOR_PARAMETER, type = Qualifier.class, elements = "\"dataSourceTwoConfig\"")
})
public interface SampleTwoDao {

}
```

## 最後に
今後とも愉快なDaoライフを満喫しましょう

## 参考
https://fumidzuki.com/knowledge/2205/