https://github.com/Adrninistrator/java-all-call-graph
以下为通过微信及搜索引擎等公共渠道找到的明确提到有使用 java-all-call-graph、java-callgraph2 的技术文章,如果不希望在这里展示,请联系我删除
https://mp.weixin.qq.com/s/pNhYzGoeCqp_zkOcNf0xgg
有使用的库:java-all-call-graph、java-callgraph2
https://mp.weixin.qq.com/s/ovzhSasR6QL7L5vlFILDgw
有使用的库:java-callgraph2
https://mp.weixin.qq.com/s/p9BcfNqLk2ZDUNcXukqXpg
有使用的库:java-callgraph2
当前项目的目标是,通过 Java 代码对 Java 代码进行自动化静态分析,将 Java 代码中非结构化的信息结构化到关系型数据库中,为 Java 应用的开发、测试、安全等场景提供有价值的信息
支持对编译后的 Java 代码进行静态分析,将相关信息写入数据库表,可使用 SQL 语句查询
支持解析 Java 中的常见数据,包括类、方法、字段、注解、泛型、方法调用、枚举等
支持解析部分常用开发框架信息,包括 MyBatis、Spring AOP、Spring Bean、Spring Controller、Spring Task 等
详细说明及使用方法见 对 Java 代码静态分析并支持 SQL 查询
支持从指定的方法开始,向上或向下生成完整的调用链
详细说明及使用方法见 静态分析生成 Java 代码方法完整调用链
支持从指定的方法开始,向上或向下生成完整的调用链后,再生成从起始方法到包含指定关键字方法的调用堆栈
详细说明及使用方法见 静态分析生成 Java 代码方法调用堆栈
支持从指定的方法开始,向上或向下生成完整的调用链后,再生成从起始方法到包含指定关键字方法的调用堆栈。在生成调用链时,支持显示能够反映业务含义的信息,例如方法调用中使用的常量值、参数类型、方法的参数或返回值的泛型类型、方法使用 MyBatis 操作的数据库表名等,支持从方法调用堆栈文件提取关注的信息
详细说明及使用方法见 从方法调用堆栈文件提取关注的信息
支持从指定的方法开始,向上或向下生成完整的调用链时,以及再生成从起始方法到包含指定关键字方法的调用堆栈时,支持获取并展示 MyBatis Mapper 方法操作的数据库表名
支持对 jar 文件的不同版本比较差异,获得生成发生变化的方法,并生成向上或向下的完整调用链,获得代码影响范围
支持根据 MyBatis Mapper XML 文件 sql 语句的变化,获得对应的 MyBatis Mapper 方法,再生成调用链及获得代码影响范围
详细说明及使用方法见 JarDiff 比较 jar 文件版本差异及代码影响范围
当 Java 应用升级使用的 JDK 或依赖库版本时,可能出现依赖库中使用了找不到的类、方法、字段的兼容问题,支持对这些问题进行扫描,也支持检查类名完全相关的类
详细说明及使用方法见 Java 应用 JDK 及依赖库兼容问题扫描工具
支持获取方法调用中的被调用对象或参数使用使用的常量值,或参数类型
详细说明及使用方法见 静态分析获取 Java 代码方法调用参数类型或值
支持对使用字符串常量、枚举常量方法调用返回值等进行字符串拼接的情况进行解析,获取拼接前的各参数内容,及拼接后的字符串值
详细说明及使用方法见 静态分析解析 Java 代码字符串拼接
已创建微信群“Java 静态分析交流@java-all-call-graph”,如果有兴趣可以加群讨论
由于群二维码只有 7 天有效期,请先添加微信,备注“jacg”,再加到群里
由于只有部分业余时间维护,所以相关的讨论和问题不能保证及时回复,请见谅
建议先在 github 提 issue 再讨论,便于整理相关内容
后续有价值且不重复的问题相关内容会整理到文档中
提问不需要注册
https://deepwiki.com/Adrninistrator/java-all-call-graph
通过大模型分析项目代码,可向大模型提出关于项目的问题,包括使用方法等
提问需要注册
https://zread.ai/Adrninistrator/java-all-call-graph
作用同上
方法调用关系是指,调用方法调用被调用方法,包括调用方法与被调用方法的包名、类名、方法名、方法参数、方法返回类型、方法调用类型(区分调用静态方法、非静态方法等)
例如 a.b.c.Caller:f1() 调用 a.b.c.Callee:f2(int,java.lang.String)
方法调用关系可以认为是调用方法与被调用方法组成的二元组
对应写入数据库的 method_call 表
方法调用信息是指,方法调用中,被调用对象或参数所使用的常量值,变量类型,变量对应的方法参数序号、其他方法调用的返回值,类的变量等信息
对应写入数据库的 method_call_info 表
对于某个 Java 项目,所有的方法调用所形成的调用图是一个非常复杂的图,例如以下为一个简单的示例:
从某个方法开始的向下的完整调用链,从该方法开始,经过该方法直接调用及间接调用的方法,最后到没有调用其他方法的方法为止
从某个方法开始的向上的完整调用链,从该方法开始,经过直接调用及间接调用该方法的方法,最后到没有被其他方法调用的方法为止
方法完整调用链是树形的结构,如下所示
com.example.Main:main(String[])
├─ com.example.service.UserService:getUserById(Long)
│ ├─ com.example.repository.UserRepository:findById(Long)
│ │ ├─ com.example.mapper.UserMapper:toEntity(ResultSet)
│ │ └─ com.example.validator.IdValidator:validate(Long)
│ └─ com.example.cache.UserCache:get(String)
└─ com.example.util.Logger:info(String)如下图所示:
从某个方法向上或向下生成的完整调用链,可以认为是所有方法的调用图中的一个子图(形状类似树,有根节点,但因为可能存在循环调用,因此是图)
方法调用堆栈是指,在方法完整调用链的基础上,从起始方法到某个调用/被调用方法之间的调用路径
方法调用堆栈是链表结构,如下所示
com.example.Main:main(String[])
└─ com.example.service.UserService:getUserById(Long)
└─ com.example.repository.UserRepository:findById(Long)
└─ com.example.mapper.UserMapper:toEntity(ResultSet)
com.example.Main:main(String[])
└─ com.example.util.Logger:info(String)如下图中红色的调用路径所示:
方法调用堆栈可以认为是该方法完整调用链中的一条调用路径
相关依赖库之间的关系如下:
java-all-call-graph 依赖 java-callgraph2,用于对 Java 代码进行静态分析
java-callgraph2 依赖 bcel,用于解析 Java 字节码信息
java-all-call-graph 依赖 druid,作为数据源
java-all-call-graph 依赖 mybatis-mysql-table-parser,用于解析 MyBatis XML 中的 MySQL 语句
mybatis-mysql-table-parser 依赖 druid,用于解析 SQL 语句
mybatis-mysql-table-parser 依赖 jdom2,用于解析 XML 文件
java-all-call-graph 依赖 java-text-to-excel,用于根据文本生成 Excel 文件
java-text-to-excel 依赖 fastexcel,用于生成 Excel 文件
如下图所示
当前项目在执行时,首先需要解析代码并写入数据库,步骤如下
java-all-call-graph 库的 RunnerWriteDb 类调用 java-callgraph2 库
java-callgraph2 库读取需要解析的 jar 等文件,进行静态分析,将分析结果写入文本文件
RunnerWriteDb 类读取以上生成的文件,写入数据库
以上 RunnerWriteDb 类的使用说明见“当前项目能够做什么”“对代码静态分析并支持 SQL 查询”部分
当被解析的代码发生变化时,需要重新执行当前步骤,使数据库中写入最新代码对应的数据
java-all-call-graph 库的其他类读取数据库数据,按要求生成数据
包括用于生成方法完整调用链、方法调用堆栈等文件的类
以上流程如下图所示:
需要使用 JDK8 及以上版本
若需要通过 IDE 打开项目源码运行,建议安装 Gradle 管理依赖库
通过配置文件指定
通过代码指定
以上两种方式的效果是相同的,每个配置文件及配置参数在代码中都存在对应项
支持以下三种格式的配置参数
当前项目中各个参数的对应两种枚举,分别是与数据库无关的配置参数、与数据库有关的配置参数
com.adrninistrator.jacg.conf.enums.ConfigKeyEnum
com.adrninistrator.jacg.conf.enums.ConfigDbKeyEnum
以上枚举对应的配置文件分别如下
_jacg_config/config.properties
_jacg_config/config_db.properties
每个枚举常量代表一个参数,参数为键值对形式,每个参数指定唯一的值
当前项目中的对应枚举为 com.adrninistrator.jacg.conf.enums.OtherConfigFileUseListEnum
每个枚举常量代表一个参数,对应一个配置文件
参数值区分顺序,可指定多个值
当前项目中的对应枚举为 com.adrninistrator.jacg.conf.enums.OtherConfigFileUseSetEnum
每个枚举常量代表一个参数,对应一个配置文件
参数值不区分顺序,可指定多个值
当前项目中的对应枚举为 com.adrninistrator.jacg.el.enums.ElConfigEnum
每个枚举常量代表一个参数,对应一个配置文件
参数值需要指定 EL 表达式,整个参数值是一个表达式
参考 配置参数示例
在代码中使用 com.adrninistrator.jacg.conf.ConfigureWrapper 类可以指定配置参数
以下为 ConfigureWrapper 用于指定配置参数的方法
| 方法名称 | 方法作用 |
|---|---|
| setMainConfig | 设置 key value 形式的参数 |
| setOtherConfigList | 设置区分顺序的参数 |
| setOtherConfigSet | 设置不区分顺序的参数 |
| setElConfigText | 设置 EL 表达式 |
不同场景下需要运行的类,参考“当前项目能够做什么”部分的对应文档
通过 IDE 打开项目源码运行
在其他项目中引用当前项目的库运行
使用项目源码构建后运行
| 运行方式 | 支持的参数配置方式 |
|---|---|
| 通过 IDE 打开项目源码运行 | 通过配置文件指定 通过代码指定 |
| 在其他项目中引用当前项目的库运行 | 通过配置文件指定 通过代码指定 |
| 使用项目源码构建后运行 | 通过配置文件指定 |
通过 IDE 打开当前项目,由 Gradle 管理依赖库,可使用源码运行
假如需要通过配置文件指定参数,可修改项目中的配置文件相关,再运行各种场景对应的入口类,在 test 模块的 test.jacg 包中
项目运行模块需要选择 test,以使 test 模块中的 log4j2 配置文件生效
假如需要通过代码指定参数,可直接执行各场景对应的示例方法,或者参考示例方法进行修改
在其他的项目中,使用 Maven/Gradle 等管理依赖库,并添加对当前项目的依赖
- 使用 Maven 管理依赖
<dependency>
<groupId>com.github.adrninistrator</groupId>
<artifactId>java-all-call-graph</artifactId>
<version>版本号</version>
</dependency>- 使用 Gradle 管理依赖
implementation("com.github.adrninistrator:java-all-call-graph: 版本号")
最新版本号可查看 https://mvnrepository.com/artifact/com.github.adrninistrator/java-all-call-graph
本工具仅引入了 slf4j-api 组件,在引入本工具组件的项目中,还需要引入 log4j2、logback 等日志组件,且保证配置正确,能够在本地正常运行
由于 Maven 间接依赖的组件版本不会自动使用最大的版本号,因此可能需要在项目中手工指定 java-all-call-graph 依赖组件的版本号,避免因为依赖组件版本不一致导致问题,可通过 java-all-call-graph 与 java-callgraph2 的 pom 文件的 dependencies 元素查看依赖组件版本
执行依赖的 java-all-call-graph 库中的 com.adrninistrator.jacg.unzip.UnzipFile 类,执行模块选择当前项目引入 java-all-call-graph 库的对应模块
当前步骤只需要执行一次,但假如 java-all-call-graph 升级后,若对配置文件有新增或修改,则需要再执行当前步骤,否则可能会因为缺少配置文件导致执行失败
以上类会将在其他项目中释放 java-all-call-graph 项目的入口类与配置文件,及 java-callgraph2 项目的配置文件
释放的根目录按照优先级如下所示:
| 释放的根目录 | 前提条件 |
|---|---|
| src/test | src/test 目录存在 |
| src/unit.test | src/test 目录不存在,src/unit.test 目录存在 |
| _jacg-{时间戳} | 以上目录都不存在 |
java-all-call-graph 项目的入口类会写入释放的根目录下的 java/test/jacg 目录,配置文件会写入释放的根目录下的 resources/目录,子目录名为_el_example,或以_jacg_开头
java-callgraph2 项目的配置文件会写入释放的根目录下的 resources/目录,子目录名为_el_example,或以_javacg2_开头
修改配置文件相关参数后,可运行对应的入口类
与“通过 IDE 打开项目源码运行”的说明相同
在项目根目录执行以下命令
gradlew gen_run_jar
构建完成后,会在项目根目录 jar_output_dir 生成相关目录及文件
| 目录、文件名 | 作用 |
|---|---|
| _el_example | 表达式相关的示例与说明文件 |
| _javacg2_xxx | 当前项目使用的配置文件保存目录 |
| config | log4j2 配置文件保存目录 |
| jar | 当前项目编译生成的 jar 文件保存目录 |
| lib | 当前项目的依赖库 jar 文件 |
| log | 保存日志文件目录,运行后会生成 |
| xxx.bat | 不同场景用于执行的脚本 |
| xxx.sh | 不同场景用于执行的脚本 |
对配置文件参数进行配置后,可执行对应的 xxx.bat 或 xxx.sh 脚本,调用对应的入口类
参考 通过代码执行的其他示例





