首页 > 编程语言 >使用最短路径算法检查项目循环依赖

使用最短路径算法检查项目循环依赖

时间:2023-10-08 10:00:52浏览次数:40  
标签:依赖 路径 List 最短 算法 循环 lineCode new 节点

最近项目组让我做一个自研的小工具,用来检查代码里的循环依赖,这里做下记录。

思路

由于工作是网络算路的,第一个想法就是通过路径计算来实现这个功能:把项目里test,resource等文件夹排除,剩下的每一个java文件可以算是对应一个类,把每个类看做是网络/路网里的节点,把类与类之间的依赖关系具象成网络里的链路或者路网里的道路,再把网络节点和链路抽象成图,这样,就可以把查找循环依赖变成查找图里每个节点两两之间是否有路径可达,如果两两之间都有路径可达,那么这两个节点代表的类就存在互相依赖。

1. 遍历项目文件

第一步,先将项目里所有java文件找出来,这里就用正常的迭代遍历文件的方法:

    public static List<File> getAllJavaClassFile(String rootPath) throws IOException {
        File project = new File(rootPath);
        return getJavaFiles(project);
    }

	private static List<File> getJavaFiles(File parentFile) throws IOException {
        List<File> javaFiles = new ArrayList<>();
        if (parentFile == null || ConfigConstant.EXCLUDE_SCAN_DIR.contains(parentFile.getName())) {
            return Lists.newArrayList();
        }
        File[] subFiles = parentFile.listFiles();
        if (subFiles == null || subFiles.length == 0) return Lists.newArrayList();
        for (File subFile : subFiles) {
            BasicFileAttributes basicFileAttributes = Files.readAttributes(subFile.toPath(), BasicFileAttributes.class);
            if (basicFileAttributes.isDirectory()) {
                javaFiles.addAll(getJavaFiles(subFile));
            } else if (basicFileAttributes.isRegularFile()) {
                String mimeType = Files.probeContentType(subFile.toPath());
                if (Objects.equals(ConfigConstant.JAVA_TYPE, mimeType)) {
                    javaFiles.add(subFile);
                }
            }
        }
        return javaFiles;
    }

2. 构造节点和依赖关系

这里需要做的操作如下:

  1. 按行读取Java文件,将第一行“package ...”读出来,将类和每一层父级包依次构造成节点(父级包也需要构造出来,有可能不是类与类的循环依赖,而是存在包与包之间的循环依赖);
  2. 将java文件中每一行"import ..."读出来,构造成节点,即此类存在依赖的类,同时构造成依赖关系。

节点结构:

@Getter
@Setter
public class ProjectItem {
    Integer id;

    String name;

    String fullName;

    Integer parent;
}

依赖关系结构:

@Getter
@Setter
public class DependNode {
    /**
     * 唯一标识,和ProjectNode里id一一对应
     */
    Integer id;

    /**
     * 标识是否是类
     */
    boolean isClass;

    /**
     * 当前节点依赖的节点
     */
    List<Integer> dependIds = new ArrayList<>();

    /**
     * 记录最下层类关系
     */
    List<Pair<Integer, Integer>> dependChildIds = new ArrayList<>();
}

转化实现:

    protected void convertFile2Item(File file, BiConsumer<String, ProjectItem> consumer) {
        ConfigParam config = ConfigParam.getIns();
        // 一行行读取,根据package和import导入语句确定依赖关系
        try (BufferedReader br = new BufferedReader(new FileReader(file))) {
            String lineCode;
            ProjectItem classItem = null;
            while ((lineCode = br.readLine()) != null) {
                if (!lineCode.contains(config.getRootItem()) || config.getExclude().stream().anyMatch(lineCode::contains)) {
                    // 这里过滤下不需要的文件,例如.git目录,test目录,resource目录以及自定义的排除目录,提供效率
                    continue;
                }
                if (lineCode.startsWith(ContextConstant.JAVA_PACKAGE_PREFIX)) {
                    // 这里根据package语句可以自上而下把包和自身类的node节点创建出来
                    classItem = createProjectItems(lineCode, file.getName().substring(0, file.getName().length() - 5));
                } else if (lineCode.startsWith(ContextConstant.JAVA_IMPORT_PREFIX)) {
                    // 这里根据import语句创建依赖的节点和包node,全量和增量进行不同处理
                    consumer.accept(lineCode, classItem);
                }
                // 读到具体的代码了,退出
                if (lineCode.contains(ContextConstant.JAVA_CLASS_START)) break;
            }
        } catch (IOException ex) {
            System.out.println(ex.getMessage());
        }
    }

注:这里import语句的解析因为项目组实际要求,需要能够读取项目全量文件和增量文件两种方式,所以我通过函数式接口的方式分开实现的。

3. 计算

这里就对抽象好的图进行计算了,由于需要对每个节点进行计算,所以使用更适合矩阵运算的Floyd算法,而不是效率更高的迪杰斯特拉算法(详见Floyd算法),具体步骤如下:

  1. 构建矩阵;
  2. Floyd计算;
  3. 对计算出来的矩阵进行过滤,将两两之间存在路径的节点找到,得到类和依赖路径;
  4. 向上浮动一层进行计算(例如第一次计算的都是类的循环依赖,然后开始算类的上层包之间的循环依赖,再算更上层的包的循环依赖,直至到根目录);
  5. 导出结果。

实现代码:

   public void cycleCalc() {
        List<PathResult> results = new ArrayList<>();
        // 从类开始寻找循环依赖,找完之后整个往上一层,到包继续寻找循环依赖,直到不存在有依赖关系的包或者向上找到了根节点
        while (!curDependNodes.isEmpty() && !curDependNodes.keySet().stream().allMatch(index ->
                Objects.equals(-1, allItems.get(index).getParent()))) {
            // 构建矩阵
            MatrixNode[][] matrix = buildMatrix();
            // 计算矩阵
            floyd(matrix);
            // 解析矩阵
            results.addAll(analyseMatrix(matrix));
            // 矩阵节点向上层迭代
            upIterate();
        }
        ExportResult.exportJson(results, allItems);
    }

注:这里就不展示每一步的具体实现了,仅提供思路。

标签:依赖,路径,List,最短,算法,循环,lineCode,new,节点
From: https://www.cnblogs.com/liu-im/p/17748202.html

相关文章

  • Mysql 分布式序列算法
    接上文Mysql分库分表1.分布式序列简介在分布式系统下,怎么保证ID的生成满足以上需求?ShardingJDBC支持以上两种算法自动生成ID。这里,使用ShardingJDBC让主键ID以雪花算法进行生成,首先配置数据库,因为默认的注解id是int类型,装不下64位,需要进行修改:#在本地和远端服务器数据......
  • destoon修改公司模块url路径com
    destoon修改公司模块url路径com,只需要修改两处即可。1、打开文件include/global.func.php,修改:$URL=DT_PATH.'com/'.$username.'/';将com改成你希望的公司模块地址即可,例如:b2b、gongsi、changjia等。2、修改网站的伪静态,将com相关的伪静态改成对应的路径即可。rewrite^/......
  • 代码随想录 | 回溯算法 ● 理论基础 ● 77. 组合
    理论基础组合问题:N个数里面按一定规则找出k个数的集合(不强调顺序)切割问题:一个字符串按一定规则,有几种切割方式子集问题:一个N个数的集合里,有多少符合条件的子集排列问题:N个数按一定规则全排列,有几种排列方式(强调顺序)棋盘问题:N皇后,解数独等回溯法模板回溯函数模板返回值以及参数返回......
  • 算法设计 - Lecture 5
     ......
  • 【JAVA】算法
    start 1.SHA-256算法(单向、验证完整性/一致性,暂时安全)1importjava.nio.charset.StandardCharsets;2importjava.security.MessageDigest;3importjava.security.NoSuchAlgorithmException;45publicclassSHA256Example{67publicstaticStringhas......
  • Lnton羚通算法算力云平台视频监控分析安全帽穿戴识别 安全帽识别预警系统
    Lnton羚通的算法算力云平台有以下显著特点:高性能、高可靠性、高可扩展性和低成本。用户可以通过该云平台获取高效、强大的算法计算服务,快速而灵活地运行各种复杂的计算模型和算法。该平台广泛涵盖机器学习、人工智能、大数据分析和图像识别等领域。此外,云平台还提供丰富的算法库和......
  • 算法:打印斐波那契数列的前30项(JS)
    打印斐波那契数列的前30项提示:斐波那契数列的前两项是1,其他项是之前两项之和1functionfibonacciIterative(n){2if(n<=0){//如果输入的n小于等于0,表示输入错误,返回错误提示3return"输入错误,请输入正整数";4}5leta=1;//初始化......
  • 算法:九九乘法表(JS)
    九九乘法表1functioncreateMultiplicationTable(){2lettable='';//创建一个空字符串用于存储乘法表3for(leti=1;i<=9;i++){//外层循环控制行数,从1到94for(letj=1;j<=i;j++){//内层循环控制每行的列数,从1到当前行数i......
  • 时序预测的深度学习算法全面盘点
    时序预测的深度学习算法全面盘点https://blog.csdn.net/qq_34160248/article/details/131349551  https://it.sohu.com/a/690057464_121124360https://zhuanlan.zhihu.com/p/393706324https://zhuanlan.zhihu.com/p/478751503https://zhuanlan.zhihu.com/p/466656425ht......
  • 最短路径问题 java实现 源代码
    最短路径问题 java实现源代码下载地址:用到的资源文件 文件名 shortPath.propertiesbegin=/u59CB/u53D1/u5730/uFF1Aclear=/u6E05/u9664clearString=/u6E05/u695A/u7ED8/u56FE/u533A/u548C/u6240/u6709/u7684/u6587/u672CdrawLine=/u7ED8/u5236/u8DEF/u5F84end=/u76EE/......