最近由于项目中多个类定义全局静态变量 导致多线程数据不一致的问题,所以写一个demo 扫描一下当前项目中所有.class文件 定义了全局静态变量的类
扫描过程中已经将Log日志对象屏蔽,后续若有新的需求,可以在添加
package com.example.demo;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
/**
* @author llf
* @Description
* @date 2023/3/19 10:13
*/
public class ScannerClassUtils {
private static final Logger log = LoggerFactory.getLogger(ScannerClassUtils.class);
private static final String STATIC = "static";
private static final String CLASS = ".class";
private static final String LOG = "log";
/**
* 注意 : 调用时将DemoApplication.class换成项目中任一类即可 主要为了获取项目的classpath
* 根据包路径扫描当前路径下所有.class文件
*
* @param basePackgePath
* @throws ClassNotFoundException
*/
public static void getClassByPackge(String basePackgePath) {
/*存放普通class*/
List<Class> generalList = new ArrayList<>();
/*存放ComponentClass*/
List<Class> componentList = new ArrayList<>();
/*存放有静态全局变量的ComponentClass*/
List<Class> staticList = new ArrayList<>();
/*获取类路径 扫描解析所有类*/
try {
parseClassPath(generalList, basePackgePath);
} catch (ClassNotFoundException e) {
log.error("类加载异常", e);
}
/*解析所有注解类*/
parseAnnotationByClass(generalList, componentList, staticList);
/*打印list*/
printList(generalList, componentList, staticList);
}
private static void parseClassPath(List<Class> generalList, String basePackgePath) throws ClassNotFoundException {
List<String> classPathList = new ArrayList<String>();
String classPath = doPath(classPathList, basePackgePath);
//这个时候我们已经得到了指定包下所有的类的绝对路径了。我们现在利用这些绝对路径和java的反射机制得到他们的类对象
for (String path : classPathList) {
//将类的绝对路径换成相对路径
path = path.replace(classPath.replace("/", "\\")
.replaceFirst("\\\\", ""), "")
.replace("\\", ".")
.replace(CLASS, "");
//添加到普通list
generalList.add(Class.forName(path));
}
}
/***
* 解析注解 看看是不是组件
* @param generalList 普通class
* @param componentList ComponentClass
* @param staticList 静态全局变量的ComponentClass
*/
private static void parseAnnotationByClass(List<Class> generalList, List<Class> componentList, List<Class> staticList) {
for (Class clazz : generalList) {
Annotation[] annotations = clazz.getAnnotations();
for (Annotation annotation : annotations) {
//非组件 不做处理
if (!annotation.annotationType().isAnnotationPresent(Component.class)) {
continue;
}
componentList.add(clazz);
Field[] declaredFields = clazz.getDeclaredFields();
boolean contains = false;
for (Field declaredField : declaredFields) {
String modifier = Modifier.toString(declaredField.getModifiers());
if (modifier.contains(STATIC) && !declaredField.getName().contains(LOG)) {
contains = true;
break;
}
}
if (contains) {
staticList.add(clazz);
}
}
}
}
/**
* 该方法会得到所有的类,将类的绝对路径写入到classPaths中
*/
private static String doPath(List<String> classPathList, String basePackgePath) {
//获得所有当前路径下所有类
if (StringUtils.isBlank(basePackgePath)) {
basePackgePath = "";
}
//首先得到项目的classpath
String classPath = Objects.requireNonNull(DemoApplication.class.getResource("/")).getPath();
//然后把我们的包名basPach转换为路径名
basePackgePath = basePackgePath.replace(".", File.separator);
//然后把classpath和basePack合并
String searchPath = classPath + basePackgePath;
File file = new File(searchPath);
if (file.isDirectory()) {
//文件夹我们就递归
File[] files = file.listFiles();
for (File f1 : Objects.requireNonNull(files)) {
doPath(f1, classPathList);
}
} else {
//标准文件我们就判断是否是class文件
if (file.getName().endsWith(CLASS)) {
//如果是class文件我们就放入我们的集合中。
classPathList.add(file.getPath());
}
}
return classPath;
}
/**
* 该方法会得到所有的类,将类的绝对路径写入到classPaths中
*/
private static void doPath(File file, List<String> classPathList) {
if (file.isDirectory()) {
//文件夹我们就递归
File[] files = file.listFiles();
for (File f1 : Objects.requireNonNull(files)) {
doPath(f1, classPathList);
}
} else {
//标准文件我们就判断是否是class文件
if (file.getName().endsWith(CLASS)) {
//如果是class文件我们就放入我们的集合中。
classPathList.add(file.getPath());
}
}
}
/**
* 结果集打印
*
* @param generalList 普通class
* @param componentList ComponentClass
* @param staticList 静态全局变量的ComponentClass
*/
private static void printList(List<Class> generalList, List<Class> componentList, List<Class> staticList) {
log.info("\n--------------------------->打印常规class<----------------------------------------");
for (Class aClass : generalList) {
log.info("[{}]", aClass);
}
log.info("\n----------------------------->打印组件class<-------------------------------------");
for (Class aClass : componentList) {
log.info("[{}]", aClass);
}
log.info("\n----------------------------->打印静态全局变量class<--------------------------------");
for (Class aClass : staticList) {
log.info("[{}]", aClass);
}
}
}
最终执行结果
通过对比两个组件class,目前看结果符合我的预期,不过可能还有一些需要优化的地方😝