CatalogDataSourceConfiguration.java

package com.ecommerce.catalog.infrastructure.datasource;

import com.zaxxer.hikari.HikariDataSource;
import io.micrometer.core.instrument.MeterRegistry;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.flyway.FlywayDataSource;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import javax.sql.DataSource;

@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(CatalogReadReplicaProperties.class)
public class CatalogDataSourceConfiguration {

    @Bean
    @Primary
    @ConfigurationProperties("spring.datasource")
    public DataSourceProperties catalogPrimaryDataSourceProperties() {
        return new DataSourceProperties();
    }

    @Bean(name = "catalogPrimaryDataSource")
    @FlywayDataSource
    @ConfigurationProperties("spring.datasource.hikari")
    public HikariDataSource catalogPrimaryDataSource(
            DataSourceProperties catalogPrimaryDataSourceProperties) {
        return catalogPrimaryDataSourceProperties.initializeDataSourceBuilder()
                .type(HikariDataSource.class)
                .build();
    }

    @Bean
    @ConfigurationProperties("ecommerce.catalog.read-replica.datasource")
    public DataSourceProperties catalogReplicaDataSourceProperties() {
        return new DataSourceProperties();
    }

    @Bean(name = "catalogReplicaDataSource")
    @ConditionalOnProperty(
            prefix = "ecommerce.catalog.read-replica",
            name = "enabled",
            havingValue = "true")
    @ConfigurationProperties("ecommerce.catalog.read-replica.datasource.hikari")
    public HikariDataSource catalogReplicaDataSource(
            @Qualifier("catalogReplicaDataSourceProperties")
            DataSourceProperties replicaProperties) {
        return replicaProperties.initializeDataSourceBuilder()
                .type(HikariDataSource.class)
                .build();
    }

    @Bean
    CatalogDataSourceMetrics catalogDataSourceMetrics(MeterRegistry meterRegistry) {
        return new CatalogDataSourceMetrics(meterRegistry);
    }

    @Bean
    @Primary
    public DataSource dataSource(
            @Qualifier("catalogPrimaryDataSource") DataSource primary,
            @Qualifier("catalogReplicaDataSource") ObjectProvider<DataSource> replicaProvider,
            CatalogReadReplicaProperties properties,
            CatalogDataSourceMetrics metrics) {
        return new CatalogRoutingDataSource(
                primary,
                replicaProvider.getIfAvailable(),
                properties,
                metrics);
    }

    @Bean
    CatalogReplicaReadAspect catalogReplicaReadAspect(
            CatalogReadReplicaProperties properties,
            CatalogDataSourceMetrics metrics) {
        return new CatalogReplicaReadAspect(properties, metrics);
    }

    @Bean
    CatalogReadConsistencyFilter catalogReadConsistencyFilter(
            CatalogDataSourceMetrics metrics) {
        return new CatalogReadConsistencyFilter(metrics);
    }
}