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

com.base4j.mybatis.config.datasource.DataSourceBuilder Maven / Gradle / Ivy

There is a newer version: 1.3.0
Show newest version
package com.base4j.mybatis.config.datasource;

import com.base4j.mybatis.config.exception.DataSourceBuildException;
import com.base4j.mybatis.tool.NullUtil;
import com.base4j.mybatis.tool.SpringContextHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.PostConstruct;
import javax.sql.DataSource;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * Created by panlc on 2017-03-14.
 */
public class DataSourceBuilder {

    public DefaultDataSourceProperties defaultDataSourceProperties = SpringContextHelper.getBeanById("defaultDataSourceProperties");

    public DynamicDataSourceProperties dynamicDataSourceProperties = SpringContextHelper.getBeanById("dynamicDataSourceProperties");

    public ApplicationProperties applicationProperties = SpringContextHelper.getBeanById("applicationProperties");

    private Map datasourceDialect = new HashMap();

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     * 主数据源配置前缀
     */
    public static final String DEFAULT_DATASOURCE_PREFIX = "default.datasource.";

    /**
     * 其他数据源配置前缀
     */
    public static final String DYNAMIC_DATASOURCE_PREFIX = "dynamic.datasource.";

    public static final String DATASOURCE_BEAN_PREFIX = "datasource-";

    public static final String MAIN_DATASOURCE_SUFFIX = "default";
    /**
     * 主数据源名称
     */
    protected final String MAIN_DATASOURCE_NAME = DATASOURCE_BEAN_PREFIX + MAIN_DATASOURCE_SUFFIX;

    protected DataSourcePoolType poolType;    //连接池类型

    protected Class poolTypeClass;            //连接池初始化类

    public Map getDatasourceDialect() {
        return datasourceDialect;
    }

    @PostConstruct
    public void calPoolType() throws ClassNotFoundException {
        initPoolInfo();
        registDataSources();
    }



    /**
     * 初始连接池信息
     *
     * @throws ClassNotFoundException
     */
    protected void initPoolInfo() {
        String defaultDatasourceId = applicationProperties.getDefaultDatasourceId();
        if (NullUtil.isNotEmpty(defaultDatasourceId)) {
            poolType = DataSourcePoolType.valueOf(defaultDatasourceId);
        } else {
            poolType = DataSourcePoolType.druid;
        }
        try {
            poolTypeClass = Class.forName(poolType.getPoolClass());
        } catch (ClassNotFoundException e) {
            throw new DataSourceBuildException(poolType.getPoolClass() + " is not found!");
        }
    }

    /**
     * 注册数据源
     */
    private void registDataSources() {
        registerDefaultDataSources();
        registerDynamicDataSources();
    }

    /**
     * 注册主数据源
     */
    private void registerDefaultDataSources() {
        Map defaultDataSourceConf = getDefaultDataSourceConf();
        if (defaultDataSourceConf != null && defaultDataSourceConf.keySet().size() == 0) {
            initTargetDefaultDataSource();
        } else {
            initConfigDefaultDataSource(defaultDataSourceConf);
        }
        setDialect(MAIN_DATASOURCE_NAME, defaultDataSourceConf);     //记录主数据源类型
    }

    private void initTargetDefaultDataSource() {
        String defaultDatasourceId = applicationProperties.getDefaultDatasourceId();
        if (NullUtil.isNotEmpty(defaultDatasourceId)) {
            throw new IllegalArgumentException("can not find the default datasource");  //TODO 更完善的提示信息
        } else {
            DataSource defaultDatasource = SpringContextHelper.getBeanById(defaultDatasourceId);
            String url = null;
            try {
                url = defaultDatasource.getConnection().getMetaData().getURL();
            } catch (SQLException e) {
                logger.error("the datasource with the id{} in spring context can't be connected", defaultDatasourceId, e);
            }
            setDialect(MAIN_DATASOURCE_NAME, url);     //记录主数据源类型
        }
    }

    public void initConfigDefaultDataSource(Map defaultDataSourceConf) {
        try {
            SpringContextHelper.addBean(poolTypeClass, MAIN_DATASOURCE_NAME,
                    defaultDataSourceConf, poolType.getInitMethod(), poolType.getDestroyMethod());  //注册主数据源
            DataSource dataSource = SpringContextHelper.getBeanById(MAIN_DATASOURCE_NAME);
            dataSource.getConnection(); //在启动时直接连接数据源
        } catch (Exception e) {
            throw new DataSourceBuildException("error occurred while build defaultDatasource", e);
        }
    }

    /**
     * 注册其他数据源
     */
    private void registerDynamicDataSources() {
        String[] dynamicDataSourceNames = getDynamicDataSourceNames();
        for (int i = 0; i < dynamicDataSourceNames.length; i++) {
            String dynamicDataSourceName = dynamicDataSourceNames[i];
            Map dynamicDataSourceConf = getDynamicDataSourceConf(dynamicDataSourceName);
            String beanId = DATASOURCE_BEAN_PREFIX + dynamicDataSourceName;
            SpringContextHelper.addBean(poolTypeClass, beanId,
                    dynamicDataSourceConf, poolType.getInitMethod(), poolType.getDestroyMethod());  //注册主数据源
            DataSource dataSource = SpringContextHelper.getBeanById(beanId);
            try {
                dataSource.getConnection(); //在启动时直接连接数据源
            } catch (SQLException e) {
                throw new RuntimeException("数据源:" + beanId + "连接出错", e);
            }
            setDialect(beanId, dynamicDataSourceConf);     //记录其他数据源类型
        }
    }


    /**
     * 获取动态数据源名称
     *
     * @return
     */
    private String[] getDynamicDataSourceNames() {
        Map> dynamicDataSource = dynamicDataSourceProperties.getDatasource();
        if (dynamicDataSource == null) {
            return new String[0];
        }
        Set keys = dynamicDataSource.keySet();
        String[] res = new String[keys.size()];

        return keys.toArray(res);
    }

    /**
     * 根据前缀获取配置信息
     *
     * @param prefix 指定的前缀,不可为''或null
     * @return 匹配的配置项
     */
    public Map getDataSourceConf(String prefix) {
        if (prefix == null || "".equals(prefix)) {
            throw new IllegalArgumentException("datasource config prefix can not be null or ''");
        }
        Map conf = new HashMap();
        if (DEFAULT_DATASOURCE_PREFIX.equals(prefix)) {
            conf = defaultDataSourceProperties.getDatasource();
        } else if (prefix.startsWith(DYNAMIC_DATASOURCE_PREFIX)) {
            Map> datasource = dynamicDataSourceProperties.getDatasource();
            for (Map.Entry> entry : datasource.entrySet()) {
                conf.putAll(entry.getValue());
            }
        }
        if (conf.keySet().size() == 0) {
            logger.warn("datasource config with the prefix {} is empty", prefix);
        }
        return conf;
    }

    /**
     * 处理特殊数据库类弄的连接URL
     *
     * @param conf     数据库配置信息
     * @param identity 要处理的数据库类型
     * @throws UnsupportedEncodingException
     */
    public void dealUrlForSpecialDataSource(Map conf, IdentityDialect identity) {
        if (conf != null) {
            String val = getUrl(conf);
            IdentityDialect identityDialect = getIdentityDialect(val);
            if (identity == identityDialect) {
                String path = this.getClass().getResource("/").getPath();
                try {
                    path = URLDecoder.decode(path, "UTF-8");
                } catch (UnsupportedEncodingException e) {
                    throw new RuntimeException("errored while deal database url");
                }
                conf.put("url", val.replace("classpath:", path));
            }
        }
    }

    public String getUrl(Map conf) {
        String key = "url";
        if (conf.containsKey(key)) {
            String url = (String) conf.get(key);
            return url;
        }
        throw new RuntimeException("url is not defined!");
    }

    /**
     * 获取默认数据源配置
     *
     * @return
     */
    private Map getDefaultDataSourceConf() {
        return getDataSourceConfigForSpecialDataSource(DEFAULT_DATASOURCE_PREFIX);
//        Map dataSourceConf = defaultDataSourceProperties.getDatasource();
//        dealUrlForSpecialDataSource(dataSourceConf, IdentityDialect.SQLITE);
//        return dataSourceConf;
    }

    /**
     * 获取动态数据源配置
     *
     * @param datasourceName 数据源名称
     * @return
     */
    private Map getDynamicDataSourceConf(String datasourceName) {
        return getDataSourceConfigForSpecialDataSource(DYNAMIC_DATASOURCE_PREFIX + datasourceName + ".");
    }

    public Map getDataSourceConfigForSpecialDataSource(String prefix) {
        Map dataSourceConf = getDataSourceConf(prefix);
        dealUrlForSpecialDataSource(dataSourceConf, IdentityDialect.SQLITE);
        return dataSourceConf;
    }

    /**
     * 获取数据库类型
     *
     * @param datasourceName
     * @return
     */
    public String getDialect(String datasourceName) {
        if (datasourceDialect.containsKey(datasourceName)) {
            return datasourceDialect.get(datasourceName);
        } else {
            throw new IllegalArgumentException("can not find a datasource with the name : " + datasourceName);
        }
    }

    /**
     * 设置数据源类型
     *
     * @param datasourceName 数据源名称
     * @param conf           数据库配置信息
     */
    protected void setDialect(String datasourceName, Map conf) {
        if (conf == null) {
            throw new IllegalArgumentException("datasource config info can not be null");
        } else {
            String url = getUrl(conf);
            if (url == null) {
                throw new IllegalArgumentException("datasource config must contains the key: url");
            } else {
                setDialect(datasourceName, url);
            }
        }
    }

    /**
     * 设置数据库类型
     *
     * @param datasourceName 数据源名称
     * @param url            数据库连接url
     */
    protected void setDialect(String datasourceName, String url) {
        datasourceDialect.put(datasourceName, getDBIdentityFromUrl(url));
    }

    /**
     * 获取数据库类型
     *
     * @param jdbcUrl 数据库连接URL
     * @return String
     */
    private String getDBIdentityFromUrl(String jdbcUrl) {
        return getIdentityDialect(jdbcUrl).name(); //TODO
    }

    /**
     * 获取数据库类型
     *
     * @param jdbcUrl 数据库连接URL
     * @return IdentityDialect
     */
    private IdentityDialect getIdentityDialect(String jdbcUrl) {
        if (jdbcUrl == null) {
            throw new IllegalArgumentException("数据库连接url不能为空");
        }
        String[] split = jdbcUrl.split("\\:");
        if (split.length < 3) {
            throw new IllegalArgumentException("数据库连接url不符合格式:jdbc:[xx]:[xxx]");
        }
        String identity = split[1]; //针对jdbc:mysql://localhost:3306/test类url获取数据库类型
        IdentityDialect identityDialect;
        try {
            identityDialect = IdentityDialect.valueOf(identity.toUpperCase());//验证数据库类型是否获取正确
        } catch (Exception e) {
            identity = split[2];    //针对jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=[database]类url获取数据库类型
            try {
                identityDialect = IdentityDialect.valueOf(identity.toUpperCase());   //验证数据库类型是否获取正确h
            } catch (Exception e2) {
                throw new IllegalArgumentException("只支持以下数据库:" + IdentityDialect.values());
            }
        }
        return identityDialect;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy