All Downloads are FREE. Search and download functionalities are using the official Maven repository.

matrix.boot.jdbc.config.DataSourceAutoConfiguration Maven / Gradle / Ivy

The newest version!
package matrix.boot.jdbc.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import lombok.extern.slf4j.Slf4j;
import matrix.boot.common.utils.AssertUtil;
import matrix.boot.common.utils.StringUtil;
import matrix.boot.jdbc.beans.DynamicDataSource;
import matrix.boot.jdbc.beans.MoreDataSource;
import matrix.boot.jdbc.enums.DataSourceType;
import matrix.boot.jdbc.metadata.DruidDataSourcePoolMetadata;
import matrix.boot.jdbc.properties.JdbcProperties;
import org.apache.shardingsphere.shardingjdbc.jdbc.core.datasource.ShardingDataSource;
import org.springframework.boot.autoconfigure.AutoConfigurationImportFilter;
import org.springframework.boot.autoconfigure.AutoConfigurationMetadata;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceUnwrapper;
import org.springframework.boot.jdbc.metadata.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.util.CollectionUtils;
import javax.sql.DataSource;
import java.util.*;

/**
 * 数据库自动装配
 * @author wangcheng
 * date 2021/8/15
 */
@EnableConfigurationProperties(JdbcProperties.class)
@ConditionalOnProperty(value = {"matrix.jdbc.enabled"})
@EnableTransactionManagement
@Slf4j
public class DataSourceAutoConfiguration {

    /**
     * jdbc配置
     */
    private final JdbcProperties jdbcProperties;

    public DataSourceAutoConfiguration(JdbcProperties jdbcProperties) {
        this.jdbcProperties = jdbcProperties;
    }

    /**
     * 数据库源信息提供者
     * @return 数据库源信息提供者
     */
    @Bean
    public DataSourcePoolMetadataProvider dataSourcePoolMetadataProvider() {
        return this::getDataSourcePoolMetadata;
    }

    /**
     * 多数据源集合
     *
     * @return 多数据源
     */
    @Bean
    @Primary
    public MoreDataSource moreDataSource() {
        //数据库创建集合
        Map dbMap = new LinkedHashMap<>();
        //加入数据库集合
        if (!CollectionUtils.isEmpty(jdbcProperties.getDbList())) {
            jdbcProperties.getDbList().forEach((key, db) -> {
                if (db.isEnabled()) {
                    dbMap.put(key, db);
                }
            });
        }
        //定义数据源集合
        LinkedHashMap dataSourceMap = new LinkedHashMap<>();
        //获取数据源类型
        DataSourceType dataSourceType = DataSourceType.getByCode(jdbcProperties.getDataSourceType());
        if (DataSourceType.DRUID.equals(dataSourceType)) {
            //德鲁伊数据源
            dbMap.forEach((key, db) -> dataSourceMap.put(key, buildDruidDataSource(jdbcProperties, db)));
        } else if (DataSourceType.Hikari.equals(dataSourceType)) {
            //Hikari数据源
            dbMap.forEach((key, db) -> dataSourceMap.put(key, buildHikariDataSource(jdbcProperties, db)));
        }
        log.info("MoreDataSource init success!");
        return new MoreDataSource(dataSourceMap);
    }

    /**
     * 构建德鲁伊数据连接池
     *
     * @param jdbcProperties jdbc参数
     * @param dbInfo         数据库参数
     * @return 德鲁伊数据源
     */
    private DruidDataSource buildDruidDataSource(JdbcProperties jdbcProperties, JdbcProperties.DB dbInfo) {
        //校验参数
        validateDBInfo(dbInfo);
        //创建德鲁伊数据源
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName(dbInfo.getDriverClass());
        dataSource.setUrl(dbInfo.getUrl());
        dataSource.setUsername(dbInfo.getUsername());
        if (!StringUtil.isEmpty(dbInfo.getPassword())) {
            dataSource.setPassword(dbInfo.getPassword());
        }
        //打开PSCache,并且指定每个连接上PSCache的大小
        dataSource.setPoolPreparedStatements(true);
        dataSource.setMaxPoolPreparedStatementPerConnectionSize(20);
        //通过connectProperties属性来打开mergeSql功能
        dataSource.setConnectionProperties("druid.stat.mergeSql=false;druid.stat.slowSqlMillis=5000");
        //合并多个DruidDataSource的监控数据
        dataSource.setUseGlobalDataSourceStat(true);
        dataSource.setMinEvictableIdleTimeMillis(300000);
        dataSource.setValidationQuery(dbInfo.getTestQuery());
        dataSource.setTestWhileIdle(false);
        dataSource.setTestOnBorrow(false);
        dataSource.setTestOnReturn(false);
        dataSource.setTimeBetweenEvictionRunsMillis(60000);
        dataSource.setMaxWait(60000);
        //最大激活数
        dataSource.setMaxActive(jdbcProperties.getMaxActivePoolSize());
        //最小空闲数
        dataSource.setMinIdle(jdbcProperties.getMinIdlePoolSize());
        //初始化连接数
        dataSource.setInitialSize(jdbcProperties.getInitialPoolSize());
        dataSource.setAsyncInit(true);
        try {
            dataSource.setFilters("stat");
        } catch (Exception e) {
            log.debug(e.getMessage(), e);
        }
        return dataSource;
    }

    /**
     * 构建Hikari数据连接池
     * @param jdbcProperties jdbc参数
     * @param dbInfo 数据库参数
     * @return Hikari数据源
     */
    private HikariDataSource buildHikariDataSource(JdbcProperties jdbcProperties, JdbcProperties.DB dbInfo) {
        //实例化类
        HikariConfig hikariConfig = new HikariConfig();
        //设置驱动
        hikariConfig.setDriverClassName(dbInfo.getDriverClass());
        //设置url
        hikariConfig.setJdbcUrl(dbInfo.getUrl());
        //数据库帐号
        hikariConfig.setUsername(dbInfo.getUsername());
        //数据库密码
        if (!StringUtil.isEmpty(dbInfo.getPassword())) {
            hikariConfig.setPassword(dbInfo.getPassword());
        }
        //最小空闲数
        hikariConfig.setMinimumIdle(jdbcProperties.getMinIdlePoolSize());
        //最大连接数
        hikariConfig.setMaximumPoolSize(jdbcProperties.getMaxActivePoolSize());
        hikariConfig.setConnectionTestQuery(dbInfo.getTestQuery());
        hikariConfig.addDataSourceProperty("cachePrepStmts", "true");
        hikariConfig.addDataSourceProperty("prepStmtCacheSize", "250");
        hikariConfig.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
        return new HikariDataSource(hikariConfig);
    }

    /**
     * 校验DB信息
     * @param dbInfo db信息
     */
    private void validateDBInfo(JdbcProperties.DB dbInfo) {
        AssertUtil.notNullTip(dbInfo.getDriverClass(), "jdbc db driverClass can not be null");
        AssertUtil.notNullTip(dbInfo.getUrl(), "jdbc db url can not be null");
        AssertUtil.notNullTip(dbInfo.getUsername(), "jdbc db username can not be null");
        AssertUtil.notNullTip(dbInfo.getPassword(), "jdbc db password can not be null");
    }

    /**
     * 排除自动装配过滤器
     */
    public static class ExcludeAutoConfigurationFilter implements AutoConfigurationImportFilter {

        private static final Set SHOULD_SKIP = new HashSet<>(Arrays.asList(
                "org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration",
                "org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration"));

        @Override
        public boolean[] match(String[] classNames, AutoConfigurationMetadata metadata) {
            boolean[] matches = new boolean[classNames.length];
            for (int i = 0; i < classNames.length; i++) {
                matches[i] = !SHOULD_SKIP.contains(classNames[i]);
            }
            return matches;
        }
    }

    /**
     * 获取数据源链接元信息
     * @return 数据源链接元信息
     */
    private DataSourcePoolMetadata getDataSourcePoolMetadata(DataSource dataSource) {
        if (dataSource == null) {
            return null;
        }
        if (dataSource instanceof HikariDataSource) {
            return new HikariDataSourcePoolMetadata(DataSourceUnwrapper.unwrap(dataSource, HikariDataSource.class));
        } else if (dataSource instanceof DruidDataSource) {
            return new DruidDataSourcePoolMetadata(DataSourceUnwrapper.unwrap(dataSource, DruidDataSource.class));
        } else if (dataSource instanceof DynamicDataSource) {
            return getDataSourcePoolMetadata(((DynamicDataSource) dataSource).getResolvedDefaultDataSource());
        } else if (dataSource instanceof ShardingDataSource) {
            Map dataSourceMap = ((ShardingDataSource) dataSource).getDataSourceMap();
            return getDataSourcePoolMetadata(dataSourceMap.values().iterator().next());
        }
        return null;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy