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

com.yuweix.kuafu.sharding.utils.ShardingUtil Maven / Gradle / Ivy

There is a newer version: 2.0.0
Show newest version
package com.yuweix.kuafu.sharding.utils;


import com.yuweix.kuafu.sharding.annotation.Sharding;
import com.yuweix.kuafu.sharding.strategy.Strategy;

import javax.persistence.Column;
import javax.persistence.Id;
import javax.persistence.Table;

import java.lang.ref.SoftReference;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


/**
 * @author yuwei
 */
public abstract class ShardingUtil {
	private static SoftReference> TABLE_NAME_REF;
	private static final Object tableNameLock = new Object();

	private static SoftReference> SELECT_SQL_REF;
	private static final Object selectSqlLock = new Object();

	private static SoftReference> SELECT_SQL_WITH_TABLE_ALIAS_REF;
	private static final Object selectSqlWithAliasLock = new Object();

	private static SoftReference>> PERSIST_FIELD_REF;
	private static final Object persistFieldLock = new Object();

	private static SoftReference, Strategy>> SHARD_STRATEGY_REF;
	private static final Object shardStrategyLock = new Object();

	private static SoftReference, FieldCol>> CLASS_PK_FIELD_REF;
	private static final Object classPkFieldLock = new Object();

	private static SoftReference, FieldCol>> CLASS_SHARDING_FIELD_REF;
	private static final Object classShardingFieldLock = new Object();


	/**
	 * 驼峰转下划线
	 * @param str
	 * @return
	 */
	private static String toUnderline(String str) {
		Pattern pattern = Pattern.compile("[A-Z]");
		Matcher matcher = pattern.matcher(str);
		StringBuffer buf = new StringBuffer(str);
		if (!matcher.find()) {
			return buf.toString();
		}
		buf = new StringBuffer();
		matcher.appendReplacement(buf, "_" + matcher.group(0).toLowerCase());
		matcher.appendTail(buf);
		String res = toUnderline(buf.toString());
		if (res.startsWith("_")) {
			res = res.substring(1);
		}
		return res;
	}

	private static Map getTableNameMap() {
		Map map = null;
		if (TABLE_NAME_REF == null || (map = TABLE_NAME_REF.get()) == null) {
			synchronized (tableNameLock) {
				if (TABLE_NAME_REF == null || (map = TABLE_NAME_REF.get()) == null) {
					map = new ConcurrentHashMap<>();
					TABLE_NAME_REF = new SoftReference<>(map);
				}
			}
		}
		return map;
	}
	/**
	 * 根据持久化类获取对应的关系表表名。
	 * @param clz
	 * @return
	 */
	public static String getTableName(Class clz) {
		String className = clz.getName();
		Map map = getTableNameMap();
		String tableName = map.get(className);
		if (tableName == null) {
			Table table = clz.getAnnotation(Table.class);
			if (table != null && !"".equals(table.name().trim())) {
				tableName = table.name().trim();
			} else {
				tableName = toUnderline(clz.getSimpleName());
				if (tableName == null || "".equals(tableName)) {
					throw new RuntimeException("Table name is not found.");
				}
			}
			map.put(className, tableName);
		}
		return tableName;
	}

	public static class FieldCol {
		private final String columnName;
		private final Field field;

		public FieldCol(String columnName, Field field) {
			this.columnName = columnName;
			this.field = field;
		}

		public String getColumnName() {
			return columnName;
		}
		public Field getField() {
			return field;
		}
	}

	private static Map getSelectSqlMap() {
		Map map = null;
		if (SELECT_SQL_REF == null || (map = SELECT_SQL_REF.get()) == null) {
			synchronized (selectSqlLock) {
				if (SELECT_SQL_REF == null || (map = SELECT_SQL_REF.get()) == null) {
					map = new ConcurrentHashMap<>();
					SELECT_SQL_REF = new SoftReference<>(map);
				}
			}
		}
		return map;
	}
	/**
	 * 根据持久化类获取对应的所有需要持久化的属性SQL。
	 * eg:id as id, user_name as userName, create_time as createTime
	 * @param clz
	 * @return
	 */
	public static String getAllColumnSql(Class clz) {
		String className = clz.getName();
		Map map = getSelectSqlMap();
		String selectSql = map.get(className);
		if (selectSql == null) {
			StringBuilder builder = new StringBuilder("");
			List fcList = getPersistFieldList(clz);
			for (int i = 0, size = fcList.size(); i < size; i++) {
				FieldCol fc = fcList.get(i);
				if (i > 0) {
					builder.append(", ");
				}
				builder.append(fc.getColumnName()).append(" as ").append(fc.getField().getName());
			}
			selectSql = builder.toString();
			map.put(className, selectSql);
		}
		return selectSql;
	}

	private static Map getSelectSqlWithTableAliasMap() {
		Map map = null;
		if (SELECT_SQL_WITH_TABLE_ALIAS_REF == null || (map = SELECT_SQL_WITH_TABLE_ALIAS_REF.get()) == null) {
			synchronized (selectSqlWithAliasLock) {
				if (SELECT_SQL_WITH_TABLE_ALIAS_REF == null || (map = SELECT_SQL_WITH_TABLE_ALIAS_REF.get()) == null) {
					map = new ConcurrentHashMap<>();
					SELECT_SQL_WITH_TABLE_ALIAS_REF = new SoftReference<>(map);
				}
			}
		}
		return map;
	}
	/**
	 * eg:a.id as id, a.user_name as userName, a.create_time as createTime
	 * @param clz
	 * @param tableAlias
	 * @return
	 */
	public static String getAllColumnSql(Class clz, String tableAlias) {
		String key = clz.getName() + "_" + tableAlias;
		Map map = getSelectSqlWithTableAliasMap();
		String selectSql = map.get(key);
		if (selectSql == null) {
			StringBuilder builder = new StringBuilder("");
			List fcList = getPersistFieldList(clz);
			for (int i = 0, size = fcList.size(); i < size; i++) {
				FieldCol fc = fcList.get(i);
				if (i > 0) {
					builder.append(", ");
				}
				builder.append(tableAlias).append(".").append(fc.getColumnName()).append(" as ").append(fc.getField().getName());
			}
			selectSql = builder.toString();
			map.put(key, selectSql);
		}
		return selectSql;
	}

	private static Map> getPersistFieldMap() {
		Map> map = null;
		if (PERSIST_FIELD_REF == null || (map = PERSIST_FIELD_REF.get()) == null) {
			synchronized (persistFieldLock) {
				if (PERSIST_FIELD_REF == null || (map = PERSIST_FIELD_REF.get()) == null) {
					map = new ConcurrentHashMap<>();
					PERSIST_FIELD_REF = new SoftReference<>(map);
				}
			}
		}
		return map;
	}
	/**
	 * 根据持久化类获取对应的所有需要持久化的属性集合
	 * @param clz
	 * @return
	 */
	public static List getPersistFieldList(Class clz) {
		String className = clz.getName();
		Map> map = getPersistFieldMap();
		List fcList = map.get(className);
		if (fcList == null) {
			fcList = getPersistFieldList0(clz);
			map.put(className, fcList);
		}
		return fcList;
	}

	/**
	 * Gets all fields of the given class and its parents (if any).
	 * @return
	 */
	private static List getPersistFieldList0(Class clz) {
		final List allFields = new ArrayList<>();
		Class currentClass = clz;
		while (currentClass != null) {
			allFields.addAll(Arrays.asList(currentClass.getDeclaredFields()));
			currentClass = currentClass.getSuperclass();
		}

		List list = new ArrayList<>();
		for (Field field: allFields) {
			Column column = field.getAnnotation(Column.class);
			if (column == null) {
				continue;
			}

			String colName = column.name();
			if ("".equals(colName.trim())) {
				colName = toUnderline(field.getName());
			}
			if (colName == null || "".equals(colName.trim())) {
				continue;
			}
			list.add(new FieldCol(colName.trim(), field));
		}
		return list;
	}

	public static Object getFieldVal(Field field, Object t) {
		if (!field.isAccessible()) {
			field.setAccessible(true);
		}
		try {
			return field.get(t);
		} catch (IllegalAccessException e) {
			throw new RuntimeException(e);
		}
	}

	private static Map, Strategy> getShardStrategyMap() {
		Map, Strategy> map = null;
		if (SHARD_STRATEGY_REF == null || (map = SHARD_STRATEGY_REF.get()) == null) {
			synchronized (shardStrategyLock) {
				if (SHARD_STRATEGY_REF == null || (map = SHARD_STRATEGY_REF.get()) == null) {
					map = new ConcurrentHashMap<>();
					SHARD_STRATEGY_REF = new SoftReference<>(map);
				}
			}
		}
		return map;
	}
	public static String getPhysicalTableName(Sharding sharding, String tableName, Object shardingVal) {
		if (sharding == null || shardingVal == null) {
			return null;
		}
		Class strategyClz = sharding.strategy();
		Map, Strategy> map = getShardStrategyMap();
		Strategy strategy = map.get(strategyClz);
		if (strategy == null) {
			try {
				strategy = strategyClz.getDeclaredConstructor().newInstance();
			} catch (Exception e) {
				throw new RuntimeException(e);
			}
			map.put(strategyClz, strategy);
		}
		return strategy.getPhysicalTableName(tableName, shardingVal);
	}

	public static String getPhysicalTableName(Class poClz, Object shardingVal) {
		String tbName = getTableName(poClz);
		List fcList = getPersistFieldList(poClz);
		for (FieldCol fc: fcList) {
			Field field = fc.getField();
			Sharding sharding = field.getAnnotation(Sharding.class);
			if (sharding != null) {
				return getPhysicalTableName(sharding, tbName, shardingVal);
			}
		}
		return tbName;
	}

	/**
	 * 获取指定持久化类的分库分表策略对象。
	 */
	public static Strategy getShardingStrategy(Class clz) {
		FieldCol fieldCol = getShardingFieldCol(clz);
		if (fieldCol == null) {
			return null;
		}
		if (!fieldCol.getField().isAnnotationPresent(Sharding.class)) {
			return null;
		}
		Sharding sharding = fieldCol.getField().getAnnotation(Sharding.class);
		if (sharding == null) {
			return null;
		}
		Class strategyClz = sharding.strategy();
		Map, Strategy> map = getShardStrategyMap();
		Strategy strategy = map.get(strategyClz);
		if (strategy == null) {
			try {
				strategy = strategyClz.getDeclaredConstructor().newInstance();
			} catch (Exception e) {
				throw new RuntimeException(e);
			}
			map.put(strategyClz, strategy);
		}
		return strategy;
	}

	private static Map, FieldCol> getClassPkFieldMap() {
		Map, FieldCol> map = null;
		if (CLASS_PK_FIELD_REF == null || (map = CLASS_PK_FIELD_REF.get()) == null) {
			synchronized (classPkFieldLock) {
				if (CLASS_PK_FIELD_REF == null || (map = CLASS_PK_FIELD_REF.get()) == null) {
					map = new ConcurrentHashMap<>();
					CLASS_PK_FIELD_REF = new SoftReference<>(map);
				}
			}
		}
		return map;
	}
	public static FieldCol getPKFieldCol(Class clz) {
		Map, FieldCol> map = getClassPkFieldMap();
		FieldCol fc = map.get(clz);

		if (fc == null) {
			Field[] fields = clz.getDeclaredFields();
			for (Field field: fields) {
				field.setAccessible(true);
				Id idAnn = field.getAnnotation(Id.class);
				if (idAnn != null) {
					Column col = field.getAnnotation(Column.class);
					fc = new FieldCol(col == null ? field.getName() : col.name(), field);
					map.put(clz, fc);
					break;
				}
			}
		}
		return fc;
	}
	public static Field getPKField(Class clz) {
		FieldCol fc = getPKFieldCol(clz);
		return fc == null ? null : fc.getField();
	}

	private static Map, FieldCol> getClassShardingFieldMap() {
		Map, FieldCol> map = null;
		if (CLASS_SHARDING_FIELD_REF == null || (map = CLASS_SHARDING_FIELD_REF.get()) == null) {
			synchronized (classShardingFieldLock) {
				if (CLASS_SHARDING_FIELD_REF == null || (map = CLASS_SHARDING_FIELD_REF.get()) == null) {
					map = new ConcurrentHashMap<>();
					CLASS_SHARDING_FIELD_REF = new SoftReference<>(map);
				}
			}
		}
		return map;
	}
	public static FieldCol getShardingFieldCol(Class clz) {
		Map, FieldCol> map = getClassShardingFieldMap();
		FieldCol fc = map.get(clz);

		if (fc == null) {
			Field[] fields = clz.getDeclaredFields();
			for (Field field: fields) {
				field.setAccessible(true);
				Sharding sAnn = field.getAnnotation(Sharding.class);
				if (sAnn != null) {
					Column col = field.getAnnotation(Column.class);
					fc = new FieldCol(col == null ? field.getName() : col.name(), field);
					map.put(clz, fc);
					break;
				}
			}
		}
		return fc;
	}
	public static Field getShardingField(Class clz) {
		FieldCol fc = getShardingFieldCol(clz);
		return fc == null ? null : fc.getField();
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy