1. 递归打印某个模块的所有类文件
public class ModuleDependencyAnalyser {
public static void main(String[] args) {
ModuleDependencyAnalyser analyser = new ModuleDependencyAnalyser();
File file = new File("xxx");
analyser.printClass(file, 0);
}
public void printClass(File file, int indent) {
printIndent(indent);
System.out.println(file.getName());
if (file.isDirectory()) {
for (File subFile : file.listFiles()) {
printClass(subFile, indent + 1);
}
}
}
public void printIndent(int indent) {
for (int i = 0; i < indent; ++ i) {
System.out.print("----");
}
}
}
2. 获取某个模块的所有类的全路径名
@UtilityClass
public class ClassUtils {
public static List<String> getAllClassesFullName(String path) {
List<File> javaFiles = getAllJavaFiles(path);
return javaFiles.stream()
.map(file -> convertToClassFullName(file, path))
.collect(Collectors.toList());
}
public static List<File> getAllJavaFiles(String path) {
File file = new File(path);
List<File> javaFiles = new ArrayList<>();
collectAllJavaFiles(file, javaFiles);
return javaFiles;
}
private static void collectAllJavaFiles(File file, List<File> javaFiles) {
if (file.isDirectory()) {
for (File subFile : file.listFiles()) {
collectAllJavaFiles(subFile, javaFiles);
}
}
if (file.getName().endsWith(".java")) {
javaFiles.add(file);
}
}
public static String convertToClassFullName(File file, String path) {
return Optional.of(file)
.map(File::getAbsolutePath)
.map(v -> v.substring(path.length() + 1)) // 截取项目路径
.map(v -> v.replaceAll("\\\\", "\\.")) // 文件路径分隔符 \ 转换为 Java 包分隔符 .
.map(v -> v.substring(0, v.length() - 5)) // 去掉 .java 后缀
.orElse(null);
}
}
测试类:
@Slf4j
public class ModuleDependencyAnalyser {
public static void main(String[] args) {
String path = "F:\\work\\project\\AthenaWeb\\athena-learning\\src\\main\\java";
List<String> classes = ClassUtils.getAllClassesFullName(path);
log.info("classes count: {}", classes.size());
}
}
3. 模块依赖分析
(1)获取每一个 Java 源代码文件中所有的 import
类。
@UtilityClass
public class ImportUtils {
@SneakyThrows
public static List<String> getAllImportClasses(File file) {
List<String> importClasses = new ArrayList<>();
List<String> lines = IOUtils.readLines(new FileInputStream(file));
for (String line : lines) {
if (line.startsWith("import")) {
String[] parts = line.split(" "); // 通过 " " 字符分割 import 行
String lastPart = parts[parts.length - 1]; // 得到包含 ; 的类命令
String importClass = lastPart.substring(0, lastPart.length() - 1); // 去掉结尾的 ; 符号
importClasses.add(importClass);
}
}
return importClasses;
}
}
(2)定义保存依赖关系的数据结构
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class DependencyData {
@JsonProperty("athena_web_class")
private String athenaWebClass;
@JsonProperty("learning_dependency")
private List<String> learningDependency;
@JsonProperty("learning_data_access_dependency")
private List<String> learningDataAccessDependency;
@JsonProperty("learning_dependency_count")
public int getLearningDependencyCount() {
return this.learningDependency.size();
}
@JsonProperty("learning_data_access_dependency_count")
public int getLearningDataAccessDependencyCount() {
return this.learningDataAccessDependency.size();
}
@JsonIgnore
public int getDependencyCount() {
return getLearningDependencyCount() + getLearningDataAccessDependencyCount();
}
public static DependencyData of(String athenaWebClass, List<String> learningDependency, List<String> learningDataAccessDependency) {
return DependencyData.builder()
.athenaWebClass(athenaWebClass)
.learningDependency(learningDependency)
.learningDataAccessDependency(learningDataAccessDependency)
.build();
}
}
(3)分析模块依赖
@Slf4j
public class ModuleDependencyAnalyser {
private static final String LEARNING_PATH = "F:\\work\\project\\AthenaWeb\\athena-learning\\src\\main\\java";
private static final String LEARNING_DATA_ACCESS_PATH = "F:\\work\\project\\AthenaWeb\\athena-data-access\\src\\main\\java";
private static final String ATHENA_WEB_PATH = "F:\\work\\project\\AthenaWeb\\athena-web\\src\\main\\java";
public static void main(String[] args) {
List<String> learningClasses = ClassUtils.getAllClassesFullName(LEARNING_PATH);
log.info("learningClasses count: {}", learningClasses.size());
List<String> learningDataAccessClasses = ClassUtils.getAllClassesFullName(LEARNING_DATA_ACCESS_PATH);
log.info("learningDataAccessClasses count: {}", learningDataAccessClasses.size());
List<DependencyData> dependencyDatas = new ArrayList<>();
List<File> allJavaFiles = ClassUtils.getAllJavaFiles(ATHENA_WEB_PATH);
for (File file : allJavaFiles) {
List<String> importClasses = ImportUtils.getAllImportClasses(file);
String athenaWebClass = ClassUtils.convertToClassFullName(file, ATHENA_WEB_PATH);
// 求 importClasses 和 learningClasses 的交集
List<String> learningDependency = ListUtils.retainAll(importClasses, learningClasses);
// 求 importClasses 和 learningDataAccessClasses 的交集
List<String> learningDataAccessDependency = ListUtils.retainAll(importClasses, learningDataAccessClasses);
// ListUtils 全路径:org.apache.commons.collections4.ListUtils
DependencyData dependencyData = DependencyData.of(athenaWebClass, learningDependency, learningDataAccessDependency);
if (dependencyData.getDependencyCount() > 0) {
dependencyDatas.add(dependencyData);
}
}
// 按照依赖数量降序排序
Collections.sort(dependencyDatas, Comparator.comparingInt(DependencyData::getDependencyCount).reversed());
String json = JsonUtils.serialize(dependencyDatas);
System.out.println(json);
}
}
JsonUtils 的实现参考:Jackson 格式化输出
网友评论