【v3.8.3】优化枚举字典数据加载,支持多包路径扫描,提升初始化性能

pull/8786/merge
JEECG 2025-09-14 11:54:01 +08:00
parent d7dc81455d
commit 152e8c7aaa
1 changed files with 133 additions and 72 deletions

View File

@ -13,31 +13,33 @@ import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.util.ClassUtils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.lang.reflect.Method;
import java.util.*;
/**
*
*
*
* @Author taoYan
* @Date 2022/7/8 10:40
**/
@Slf4j
public class ResourceUtil {
/**
*
*
*
*
*/
private final static String[] BASE_SCAN_PACKAGES = {
"org.jeecg.common.constant.enums",
"org.jeecg.modules.message.enums"
};
/**
*
*/
private final static Map<String, List<DictModel>> enumDictData = new HashMap<>(5);
/**
* java
*/
private final static String CLASS_PATTERN="/**/*.class";
/**
* java
*/
@ -45,9 +47,9 @@ public class ResourceUtil {
private final static String CLASS_ENUM_PATTERN="/**/*Enum.class";
/**
* org.jeecg
*
*/
private final static String BASE_PACKAGE = "org.jeecg";
private static volatile boolean initialized = false;
/**
*
@ -55,59 +57,135 @@ public class ResourceUtil {
private final static String METHOD_NAME = "getDictList";
/**
*
* SysDictServiceImpl#queryAllDictItems()
* @return
*
* @return
*/
public static Map<String, List<DictModel>> getEnumDictData(){
if(enumDictData.keySet().size()>0){
return enumDictData;
}
ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + ClassUtils.convertClassNameToResourcePath(BASE_PACKAGE) + CLASS_ENUM_PATTERN;
try {
Resource[] resources = resourcePatternResolver.getResources(pattern);
MetadataReaderFactory readerFactory = new CachingMetadataReaderFactory(resourcePatternResolver);
for (Resource resource : resources) {
MetadataReader reader = readerFactory.getMetadataReader(resource);
String classname = reader.getClassMetadata().getClassName();
Class<?> clazz = Class.forName(classname);
EnumDict enumDict = clazz.getAnnotation(EnumDict.class);
if (enumDict != null) {
EnumDict annotation = clazz.getAnnotation(EnumDict.class);
String key = annotation.value();
if(oConvertUtils.isNotEmpty(key)){
List<DictModel> list = (List<DictModel>) clazz.getDeclaredMethod(METHOD_NAME).invoke(null);
enumDictData.put(key, list);
}
public static Map<String, List<DictModel>> getEnumDictData() {
if (!initialized) {
synchronized (ResourceUtil.class) {
if (!initialized) {
long startTime = System.currentTimeMillis();
log.info("【枚举字典加载】开始初始化枚举字典数据...");
initEnumDictData();
initialized = true;
long endTime = System.currentTimeMillis();
log.info("【枚举字典加载】枚举字典数据初始化完成,共加载 {} 个字典,总耗时: {}ms", enumDictData.size(), endTime - startTime);
}
}
}catch (Exception e){
log.error("获取枚举类字典数据异常", e.getMessage());
// e.printStackTrace();
}
return enumDictData;
}
/**
* SysDictServiceImpl#queryManyDictByKeys(java.util.List, java.util.List)
* @param dictCodeList
* @param keys
* @return
* 使
*/
public static Map<String, List<DictModel>> queryManyDictByKeys(List<String> dictCodeList, List<String> keys){
if(enumDictData.keySet().size()==0){
getEnumDictData();
private static void initEnumDictData() {
ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
long scanStartTime = System.currentTimeMillis();
List<Resource> allResources = new ArrayList<>();
// 扫描多个包路径
for (String basePackage : BASE_SCAN_PACKAGES) {
String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + ClassUtils.convertClassNameToResourcePath(basePackage) + CLASS_ENUM_PATTERN;
try {
Resource[] resources = resourcePatternResolver.getResources(pattern);
allResources.addAll(Arrays.asList(resources));
log.debug("【枚举字典加载】扫描包 {} 找到 {} 个枚举类文件", basePackage, resources.length);
} catch (Exception e) {
log.warn("【枚举字典加载】扫描包 {} 时出现异常: {}", basePackage, e.getMessage());
}
}
long scanEndTime = System.currentTimeMillis();
log.info("【枚举字典加载】文件扫描完成,总共找到 {} 个枚举类文件,扫描耗时: {}ms", allResources.size(), scanEndTime - scanStartTime);
MetadataReaderFactory readerFactory = new CachingMetadataReaderFactory(resourcePatternResolver);
long processStartTime = System.currentTimeMillis();
int processedCount = 0;
for (Resource resource : allResources) {
try {
MetadataReader reader = readerFactory.getMetadataReader(resource);
String classname = reader.getClassMetadata().getClassName();
// 提前检查是否有@EnumDict注解避免不必要的Class.forName
if (hasEnumDictAnnotation(reader)) {
processEnumClass(classname);
processedCount++;
}
} catch (Exception e) {
log.debug("处理资源异常: {} - {}", resource.getFilename(), e.getMessage());
}
}
long processEndTime = System.currentTimeMillis();
log.info("【枚举字典加载】处理完成,实际处理 {} 个带注解的枚举类,处理耗时: {}ms", processedCount, processEndTime - processStartTime);
}
/**
* EnumDict
*/
private static boolean hasEnumDictAnnotation(MetadataReader reader) {
try {
return reader.getAnnotationMetadata().hasAnnotation(EnumDict.class.getName());
} catch (Exception e) {
return false;
}
}
/**
*
*/
private static void processEnumClass(String classname) {
try {
Class<?> clazz = Class.forName(classname);
EnumDict enumDict = clazz.getAnnotation(EnumDict.class);
if (enumDict != null) {
String key = enumDict.value();
if (oConvertUtils.isNotEmpty(key)) {
Method method = clazz.getDeclaredMethod(METHOD_NAME);
List<DictModel> list = (List<DictModel>) method.invoke(null);
enumDictData.put(key, list);
log.debug("成功加载枚举字典: {} -> {}", key, classname);
}
}
} catch (Exception e) {
log.debug("处理枚举类异常: {} - {}", classname, e.getMessage());
}
}
/**
* SysDictServiceImpl#queryManyDictByKeys(java.util.List, java.util.List)
*
* @param dictCodeList
* @param keys
* @return
*/
public static Map<String, List<DictModel>> queryManyDictByKeys(List<String> dictCodeList, List<String> keys) {
Map<String, List<DictModel>> enumDict = getEnumDictData();
Map<String, List<DictModel>> map = new HashMap<>();
for (String code : enumDictData.keySet()) {
if(dictCodeList.indexOf(code)>=0){
List<DictModel> dictItemList = enumDictData.get(code);
for(DictModel dm: dictItemList){
// 使用更高效的查找方式
Set<String> dictCodeSet = new HashSet<>(dictCodeList);
Set<String> keySet = new HashSet<>(keys);
for (String code : enumDict.keySet()) {
if (dictCodeSet.contains(code)) {
List<DictModel> dictItemList = enumDict.get(code);
for (DictModel dm : dictItemList) {
String value = dm.getValue();
if(keys.indexOf(value)>=0){
if (keySet.contains(value)) {
List<DictModel> list = new ArrayList<>();
list.add(new DictModel(value, dm.getText()));
map.put(code,list);
map.put(code, list);
break;
}
}
@ -115,22 +193,5 @@ public class ResourceUtil {
}
return map;
}
/**
*
*
* @param classPath
*/
public static Object getImplementationClass(String classPath){
try {
Class<?> aClass = Class.forName(classPath);
return SpringContextUtils.getBean(aClass);
} catch (ClassNotFoundException e) {
log.error("类没有找到",e);
return null;
} catch (NoSuchBeanDefinitionException e){
log.error(classPath + "没有实现",e);
return null;
}
}
}
}