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

gu.sql2java.druid.DruidDataSourceFactory Maven / Gradle / Ivy

There is a newer version: 5.2.0
Show newest version
package gu.sql2java.druid;

import java.io.Closeable;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.regex.Pattern;

import javax.sql.DataSource;

import com.google.common.base.Throwables;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;

import gu.sql2java.DataSourceConfig;
import gu.sql2java.DataSourceFactory;
import gu.sql2java.utils.CaseSupport;

import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Strings.nullToEmpty;
import static gu.sql2java.SimpleLog.log;
import static gu.sql2java.DataSourceConfig.logDatabaseProperties;
import static com.alibaba.druid.pool.DruidDataSourceFactory.PROP_URL; 
import static com.alibaba.druid.pool.DruidDataSourceFactory.PROP_DRIVERCLASSNAME; 
import static com.alibaba.druid.pool.DruidDataSourceFactory.PROP_USERNAME; 
import static com.alibaba.druid.pool.DruidDataSourceFactory.PROP_PASSWORD; 

/**
 * 基于druid实现{@link DataSourceFactory}接口
 * @author guyadong
 *
 */
public class DruidDataSourceFactory implements DataSourceFactory{
	private static final String jdbcPrefix = "jdbc.";
	private static final String c3p0Prefix = "c3p0.";
	private static final String springDatasourcePrefix = "spring.datasource.";
	private static final String springDatasourceDruidPrefix = "spring.datasource.druid.";
	private static final String druidPrefix = "druid.";
	private static final String driverSuffix = ".driver";
	/** {@link com.alibaba.druid.pool.DruidDataSourceFactory}所有属性名 */
	private static final Set druidProperyNames = Sets.newHashSet(getDuridPropertyNames().values());
	public DruidDataSourceFactory() {
	}
	
    /** 
     * if not contain sub key without prefix,rename key to sub key without prefix ,and convert to camel-case string
     */
    private static boolean renameKey(Properties props,String key,String prefix){
    	return renameKey(props,key,prefix,null);
    }
    /**
     * if not contain sub key without prefix,rename key to sub key without prefix ,and convert to camel-case string
     * @param props
     * @param key 
     * @param prefix
     * @param newPrefix new prefix if not empty or null
     */
    private static boolean renameKey(Properties props,String key,String prefix,String newPrefix){
    	if(key.startsWith(prefix)){
    		Object value = props.remove(key);
    		String subKey = key.substring(prefix.length());
    		String camelcaseKey = subKey;
    		if(Pattern.compile("[-_]").matcher(subKey).find()){
    			camelcaseKey = CaseSupport.toCamelcase(subKey.replace('-', '_').toLowerCase());    			
    		}
    		/** 统一改为驼峰命名(camel-case) */
    		if(!props.containsKey(camelcaseKey) && !props.containsKey(nullToEmpty(newPrefix) + camelcaseKey)){
    			props.put(nullToEmpty(newPrefix) + camelcaseKey, value);
    		}
    		return true;
    	}
    	return false;
    }
    
    private static void replaceKey(Properties props,String from,String to){
		if(props.containsKey(from)){
			/** 对于命名格式不匹配的参数改名 */
			Object value = props.remove(from);
			props.put(to, value);
		}else if(props.containsKey(druidPrefix + from)){
			/** 对于命名格式不匹配的参数改名 */
			Object value = props.remove(druidPrefix + from);
			props.put(to, value);
		}
	}

	/** 
     * 归一化{@link Properties}配置参数
* 如果参数名有{@code prefix}前缀,则将参数前缀改为{@link newPrefix},参数名改为驼峰命名, * 如果参数名有 c3p0.前缀则将参数删除, * 将driver参数改名为driverClassName, */ private static void normalizePropertiesForDurid0(Properties props,String prefix,String newPrefix){ props.stringPropertyNames().forEach(k->{ if(k.startsWith(prefix)){ /** rename key ,remove jdbc. */ renameKey(props, k, prefix,newPrefix); }else if (k.startsWith(c3p0Prefix)){ /** remove key with prefix c3p0. */ props.remove(k); return ; } if(k.endsWith(driverSuffix)){ /** rename .driver to .driverClassName */ Object value = props.remove("driver"); props.put(PROP_DRIVERCLASSNAME, value); } }); } /** * 将{@link Properties}配置归一化为 Druid 可识别的配置参数 * 如果参数名有 jdbc.,spring.datasource.druid.,spring.datasource.,druid.前缀,则将参数改名(camel-case)删除前缀 * 如果参数名有 c3p0.前缀,或非单级参数(包含.)则将参数删除 * 将driver参数改名为driverClassName * 删除所有非druid参数名 */ static void normalizePropertiesForDurid(Properties props){ normalizePropertiesForDurid0(props,jdbcPrefix,null); normalizePropertiesForDurid0(props,druidPrefix,druidPrefix); normalizePropertiesForDurid0(props,springDatasourceDruidPrefix,druidPrefix); normalizePropertiesForDurid0(props,springDatasourcePrefix,null); /** 检查props中的参数名 */ druidProperyNames.forEach(n->{ if(props.containsKey(n)){ // DO NOTHING }else if(props.containsKey(druidPrefix + n)){ renameKey(props, druidPrefix + n, druidPrefix); }else if(n.startsWith(druidPrefix)){ // DO NOTHING }else if(Pattern.compile("[-_]").matcher(n).find()){ /** 转为驼峰命名尝试查找 */ String camelcaseKey = CaseSupport.toCamelcase(n.replace('-', '_').toLowerCase()); replaceKey(props,camelcaseKey,n); }else{ /** 转为鱼骨命名尝试查找 */ String spinalcaseKey = CaseSupport.toSnakecase(n).replace('_', '-'); replaceKey(props,spinalcaseKey,n); } }); props.stringPropertyNames().forEach(k->{ if (k.indexOf('.') >= 0 && !k.startsWith(druidPrefix)){ /** remove any key with dot */ props.remove(k); return ; } }); } /** * 从{@link com.alibaba.druid.pool.DruidDataSourceFactory}获取所有PROP_前缀的静态常量值
*
    *
  • K --- 常量字段名
  • *
  • V --- 常量字段值(DRUID配置属性名)
  • *
*/ private static Map getDuridPropertyNames(){ Iterable constFields = Iterables.filter(Arrays.asList(com.alibaba.druid.pool.DruidDataSourceFactory.class.getFields()), f->f.getName().startsWith("PROP_") && f.getType().equals(String.class) && Modifier.isStatic(f.getModifiers()) && Modifier.isFinal(f.getModifiers())); Map duridConstPopertyNames = Maps.newHashMap(); constFields.forEach(f->{ try { duridConstPopertyNames.put(f.getName(), (String)f.get(null)); } catch (IllegalArgumentException | IllegalAccessException e) { Throwables.throwIfUnchecked(e); throw new RuntimeException(e); } }); return duridConstPopertyNames; } /** * 根据{@link Properties}提供的参数创建{@link DataSource}实例 * @param input */ public static DataSource createDataSource(Properties input){ Properties props = new Properties(); props.putAll(checkNotNull(input,"props is null")); try{ normalizePropertiesForDurid(props); checkArgument(props.containsKey(PROP_URL),"MISSING ESSENTIAL ARGUMENT %s",PROP_URL); logDatabaseProperties(props, "druid"); return com.alibaba.druid.pool.DruidDataSourceFactory.createDataSource(props); }catch (Exception e){ String message = String.format("can't get connection by argument...url/username/password[%s/%s/%s]", props.getProperty(PROP_URL),props.getProperty(PROP_USERNAME),props.getProperty(PROP_PASSWORD)); throw new IllegalArgumentException(message,e); } } @Override public DataSource createDataSource(DataSourceConfig config){ Properties props = new Properties(); props.putAll(checkNotNull(config,"config is null").getInitProperties()); return createDataSource(props); } @Override public void destroy(DataSource dataSource){ try{ if(dataSource instanceof Closeable){ ((Closeable)dataSource).close(); } }catch (Exception e) { log("dispose DruidDataSource wrong ..." + e); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy