STableManager.java 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440
  1. package manager;
  2. import com.fasterxml.jackson.databind.DeserializationFeature;
  3. import com.fasterxml.jackson.databind.ObjectMapper;
  4. import org.slf4j.Logger;
  5. import org.slf4j.LoggerFactory;
  6. import util.ClassLoaderHelper;
  7. import util.StringUtil;
  8. import util.SysUtil;
  9. import java.io.*;
  10. import java.lang.reflect.Field;
  11. import java.lang.reflect.Method;
  12. import java.util.*;
  13. import java.util.concurrent.ConcurrentHashMap;
  14. public class STableManager {
  15. private static final Logger LOGGER = LoggerFactory.getLogger(STableManager.class);
  16. /**
  17. * table表包名
  18. */
  19. private static String data_parackage = null;
  20. private static String jsonPath;
  21. private static int currentDbVersion;
  22. /**
  23. * des 配置类缓存
  24. * 1 懒加载 各个模块各取所需
  25. * 2 为了热更新 整体替换 避免表相互依赖造成的安全问题
  26. * 3 为保证所有数据一致性 做了以下处理
  27. * a 去掉了配置类中静态配置数据 所有获取都应该从此map中拿 保证最新和一致
  28. */
  29. private static final Map<String, Object> tableBeanMap = new ConcurrentHashMap<>();
  30. /**
  31. * des 模块内的配置2次处理的静态数据
  32. * 1 模块数据和纯配置数据分离
  33. * 2 为了热更新 整体替换 避免表相互依赖造成的安全问题
  34. */
  35. private static final Map<String, AbstractClassStaticConfig> classStaticConfigMap = new ConcurrentHashMap<>();
  36. public static void initialize(String data_parackage) throws Exception {
  37. STableManager.data_parackage = data_parackage;
  38. updateTablesWithTableNames(false);
  39. initJsonPath();
  40. initDbVersion();
  41. }
  42. /**
  43. * 根据表名字更新表数据
  44. *
  45. * @throws Exception
  46. */
  47. public static void updateTablesWithTableNames(boolean isHotFix) throws Exception {
  48. String[] tableList = null;
  49. if (isHotFix) {
  50. CDataBaseVersion version = getJsonFilePathInJsonConf("c_database_version.json", CDataBaseVersion.class);
  51. if (version == null || version.getTables().isEmpty() || currentDbVersion >= version.getVersion()) { // 启动而不是热更
  52. return;
  53. }
  54. currentDbVersion = version.getVersion();
  55. //更新指定表
  56. tableList = version.getTables().split("\\|");
  57. }
  58. Set<Class<?>> messageCommandClasses = ClassScanner.listClassesWithAnnotation(data_parackage, Table.class);
  59. for (Class<?> cls : messageCommandClasses) {
  60. String tableName = cls.getAnnotation(Table.class).name();
  61. if (tableList != null) {
  62. if (!isHotFixContainTableName(tableList, tableName)) {
  63. continue;
  64. }
  65. //TODO 应该说有数据都加载后统一替换 但是现在部分静态数据遗留在cfg类中 只能一个一个加载
  66. if(!tableName.equals("Map"))
  67. loadInCache(cls);
  68. LOGGER.info("hotfix table"+tableName);
  69. }
  70. Object stable = cls.newInstance();
  71. Method method = cls.getMethod("init");
  72. method.invoke(stable);
  73. }
  74. try {
  75. //加载逻辑数据
  76. Set<String> staticConfigsNames = new HashSet<>();
  77. Set<String> tables = null;
  78. if (tableList != null) {
  79. tables = new HashSet<>(Arrays.asList(tableList));
  80. }
  81. for (Map.Entry<String, AbstractClassStaticConfig> entry : classStaticConfigMap.entrySet()) {
  82. if (tables != null && entry.getValue().checkChange(tables).size() <= 0) {
  83. continue;
  84. }
  85. staticConfigsNames.add(entry.getKey());
  86. }
  87. List<Class<?>> staticConfigsclass = new LinkedList<>();
  88. try {
  89. ClassLoaderHelper.findLocalClass("com.ljsd.jieling.config.clazzStaticCfg", AbstractClassStaticConfig.class,Thread.currentThread().getContextClassLoader(), staticConfigsclass);
  90. }catch (RuntimeException e){
  91. }
  92. try {
  93. ClassLoaderHelper.findClassJar("com.ljsd.jieling.config.clazzStaticCfg", AbstractClassStaticConfig.class, Thread.currentThread().getContextClassLoader(), staticConfigsclass);
  94. }catch (RuntimeException e){
  95. }
  96. for (Class<?> cls : staticConfigsclass) {
  97. if (tables != null) {
  98. if(!staticConfigsNames.contains(cls.getName())){
  99. continue;
  100. }
  101. }
  102. AbstractClassStaticConfig newClassConfig = (AbstractClassStaticConfig) cls.newInstance();
  103. classStaticConfigMap.put(cls.getName(), newClassConfig);
  104. }
  105. } catch (InstantiationException | IllegalAccessException e2) {
  106. LOGGER.error("e={}",e2);
  107. }
  108. }
  109. private static void registFigureConfig(AbstractClassStaticConfig classStaticConfig) {
  110. if (classStaticConfig == null) {
  111. return;
  112. }
  113. classStaticConfigMap.put(classStaticConfig.getClass().getName(), classStaticConfig);
  114. }
  115. /**
  116. * 获取类的二次处理配置类
  117. */
  118. public static <T extends AbstractClassStaticConfig> T getFigureConfig(Class<T> tClass) {
  119. if (!classStaticConfigMap.containsKey(tClass.getName())) {
  120. if (ClassLoaderHelper.filter(tClass, AbstractClassStaticConfig.class)) {
  121. try {
  122. registFigureConfig((AbstractClassStaticConfig) tClass.newInstance());
  123. } catch (Exception e) {
  124. }
  125. }
  126. }
  127. return (T) classStaticConfigMap.get(tClass.getName());
  128. }
  129. private static boolean isHotFixContainTableName(String[] tableNames, String curTableName) {
  130. if (tableNames == null) {
  131. return false;
  132. }
  133. if (tableNames.length == 0) {
  134. return false;
  135. }
  136. for (String oneTable : tableNames) {
  137. if (oneTable.equalsIgnoreCase(curTableName)) {
  138. return true;
  139. }
  140. }
  141. return false;
  142. }
  143. /**
  144. * 读取配置表到内存
  145. */
  146. @SuppressWarnings("unchecked")
  147. public static <T> Map<Integer, T> getConfig(Class<T> clazz) {
  148. Object o = tableBeanMap.get(clazz.getName());
  149. if (null == o) {
  150. o = loadInCache(clazz);
  151. }
  152. java.util.TreeMap<Integer, T> result = null;
  153. try {
  154. result = (java.util.TreeMap<Integer, T>) o;
  155. } catch (ClassCastException e) {
  156. e.printStackTrace();
  157. }
  158. if (null == result) {
  159. throw new NullPointerException("clazz.null" + clazz.getName());
  160. }
  161. return result;
  162. }
  163. private static <T> Object loadInCache(Class<T> clazz){
  164. TreeMap<Integer, T> map = new TreeMap<>();
  165. try {
  166. String tableName = clazz.getAnnotation(Table.class).name();
  167. // String path = SysUtil.getPath("conf", "server", tableName + ".txt");
  168. String path = "conf/server/"+tableName+".txt";
  169. File file = new File(path);
  170. if (!file.exists()) {
  171. LOGGER.error("file not find {}, do not find sheet with {} you need rebuild all sheet by gen sheet tool!", path, tableName);
  172. throw new NullPointerException("clazz.null" + clazz.getName());
  173. }
  174. LOGGER.info("initMap:{}", clazz.getSimpleName());
  175. readFileToCache(clazz, map, file);
  176. } catch (Exception e) {
  177. e.printStackTrace();
  178. }
  179. tableBeanMap.put(clazz.getName(), map);
  180. return map;
  181. }
  182. private static <T> void readFileToCache(Class<T> clazz, Map<Integer, T> map, File file) throws IOException, InstantiationException, IllegalAccessException, NoSuchFieldException {
  183. String line;
  184. List<String> key = new ArrayList<>();
  185. List<String> type = new ArrayList<>();
  186. int lineNum = 0;
  187. try (BufferedReader bufferedReader = new BufferedReader(new FileReader(file))) {
  188. while ((line = bufferedReader.readLine()) != null) {
  189. if (line.isEmpty()) {
  190. continue;
  191. }
  192. T obj = clazz.newInstance();
  193. String[] prarms = line.split("\\t");
  194. switch (lineNum) {
  195. case 0:
  196. prarms = StringUtil.fieldHandle(prarms);
  197. key.addAll(Arrays.asList(prarms));
  198. break;
  199. case 1:
  200. type.addAll(Arrays.asList(prarms));
  201. break;
  202. default:
  203. try {
  204. dealParams(clazz, map, key, type, obj, prarms);
  205. }catch (Exception e){
  206. LOGGER.error("clazz = {}, line = {}, para = {}, excep = {}",clazz, line.substring(0,10), Arrays.toString(prarms), e);
  207. throw e;
  208. }
  209. break;
  210. }
  211. lineNum++;
  212. }
  213. }
  214. }
  215. /**
  216. * 读取配置表到内存
  217. */
  218. public static <T> Map<Integer, Map<Integer, T>> getMapConfig(Class<T> clazz) {
  219. Map<Integer, Map<Integer, T>> map = new HashMap<>();
  220. try {
  221. String tableName = clazz.getAnnotation(Table.class).name();
  222. String pathDir = "conf/server/";
  223. File mapDir = new File(pathDir);
  224. String prefix = tableName + "_";
  225. int preLength = prefix.length();
  226. for (File mapFile : mapDir.listFiles()) {
  227. tableName = mapFile.getName();
  228. if (!mapFile.getName().startsWith(prefix)) {
  229. continue;
  230. }
  231. int mapId = Integer.parseInt(tableName.substring(preLength).split("\\.")[0]);
  232. LOGGER.info("initMap:{}", tableName);
  233. Map<Integer, T> mapConf = new HashMap<>();
  234. readFileToCache(clazz, mapConf, mapFile);
  235. map.put(mapId, mapConf);
  236. }
  237. } catch (Exception e) {
  238. e.printStackTrace();
  239. LOGGER.error("getMapConfig= {}", e.toString());
  240. }
  241. return map;
  242. }
  243. /**
  244. * 处理参数
  245. */
  246. private static <T> void dealParams(Class<T> clazz, Map<Integer, T> map, List<String> key, List<String> type, T obj, String[] prarms) throws NoSuchFieldException, IllegalAccessException {
  247. int id = Integer.parseInt(prarms[0]);
  248. for (int i = 0; i < prarms.length; i++) {
  249. try {
  250. Field field = clazz.getDeclaredField(key.get(i));
  251. boolean flag = field.isAccessible();
  252. field.setAccessible(true);
  253. switch (type.get(i)) {
  254. case "int":
  255. field.set(obj, Integer.parseInt(prarms[i]));
  256. break;
  257. case "string":
  258. case "stringt":
  259. if (!"null".equalsIgnoreCase(prarms[i]) || !"".equalsIgnoreCase(prarms[i])) {
  260. field.set(obj, prarms[i]);
  261. }
  262. break;
  263. case "long":
  264. field.set(obj, Long.parseLong(prarms[i]));
  265. break;
  266. case "double":
  267. field.set(obj, Double.parseDouble(prarms[i]));
  268. break;
  269. case "float":
  270. field.set(obj, Float.parseFloat(prarms[i]));
  271. break;
  272. case "bool":
  273. field.set(obj, Boolean.parseBoolean(prarms[i]));
  274. break;
  275. default:
  276. if (type.get(i).startsWith("ref")) {
  277. field.set(obj, Integer.parseInt(prarms[i]));
  278. } else if (type.get(i).startsWith("mut")) {
  279. mut(key, type, obj, prarms, i, field);
  280. }
  281. break;
  282. }
  283. field.setAccessible(flag);
  284. map.put(id, obj);
  285. } catch (NoSuchFieldException e) {
  286. e.printStackTrace();
  287. LOGGER.error("Key={} Clazz={} Exception={}", key.get(i), clazz, e.toString());
  288. }
  289. }
  290. }
  291. /**
  292. * 操作mut开头的类型
  293. */
  294. private static <T> void mut(List<String> key, List<String> type, T obj, String[] prarms, int i, Field field) throws IllegalAccessException {
  295. String[] params = type.get(i).split(",");
  296. String[] type1 = params[1].split("#");
  297. int dimension = dimension(type1, params);
  298. if (dimension == 0) {
  299. field.set(obj, prarms[i]);
  300. } else {
  301. //全为int或者float
  302. switch (type1[0]) {
  303. case "int":
  304. intField(obj, prarms, i, field, dimension);
  305. break;
  306. case "float":
  307. floatField(obj, prarms, i, field, dimension);
  308. break;
  309. default:
  310. break;
  311. }
  312. }
  313. }
  314. private static <T> void floatField(T obj, String[] prarms, int i, Field field, int dimension) throws IllegalAccessException {
  315. switch (dimension) {
  316. case 1:
  317. field.set(obj, StringUtil.parseFiledFloat(prarms[i]));
  318. break;
  319. case 2:
  320. field.set(obj, StringUtil.parseFiledFloat2(prarms[i]));
  321. break;
  322. case 3:
  323. field.set(obj, StringUtil.parseFiledFloat3(prarms[i]));
  324. break;
  325. default:
  326. break;
  327. }
  328. }
  329. private static <T> void intField(T obj, String[] prarms, int i, Field field, int dimension) throws IllegalAccessException {
  330. switch (dimension) {
  331. case 1:
  332. field.set(obj, StringUtil.parseFiledInt(prarms[i]));
  333. break;
  334. case 2:
  335. field.set(obj, StringUtil.parseFiledInt2(prarms[i]));
  336. break;
  337. case 3:
  338. field.set(obj, StringUtil.parseFiledInt3(prarms[i]));
  339. break;
  340. default:
  341. break;
  342. }
  343. }
  344. /**
  345. * 判断是几维数组
  346. */
  347. private static int dimension(String type[], String[] params) throws IllegalAccessException {
  348. String type1 = type[0];
  349. boolean flag = false;
  350. for (int i = 0; i < type.length; i++) {
  351. if (!type1.equals(type[i])) {
  352. flag = true;
  353. }
  354. }
  355. if (flag) {
  356. return 0;
  357. }
  358. return Integer.parseInt(params[2]);
  359. }
  360. private static String getType(String param) {
  361. String[] params = param.split(",");
  362. String[] type = params[1].split("#");
  363. return type[0];
  364. }
  365. public static <T> T getJsonFilePathInJsonConf(String fileName, Class<T> fileClass) {
  366. File file = new File(jsonPath + fileName);
  367. if (!file.exists()) {
  368. LOGGER.info("the {} is not exist", fileName);
  369. return null;
  370. }
  371. try (InputStream in = new FileInputStream(file);) {
  372. ObjectMapper mapper = new ObjectMapper();
  373. mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
  374. return mapper.readValue(in, fileClass);
  375. } catch (FileNotFoundException e) {
  376. e.printStackTrace();
  377. } catch (IOException e) {
  378. e.printStackTrace();
  379. }
  380. return null;
  381. }
  382. private static void initJsonPath() {
  383. String osName = System.getProperty("os.name");
  384. jsonPath = "../conf/";
  385. if (osName.matches("^(?i)Windows.*$")) {// Window 系统
  386. jsonPath = "conf/";
  387. }
  388. }
  389. private static void initDbVersion() {
  390. CDataBaseVersion cDataBaseVersion = getJsonFilePathInJsonConf("c_database_version.json", CDataBaseVersion.class);
  391. if (null == cDataBaseVersion) {
  392. currentDbVersion = 0;
  393. } else {
  394. currentDbVersion = cDataBaseVersion.getVersion();
  395. }
  396. }
  397. }