面试题答案
一键面试插件架构设计
- 核心功能模块:负责分析模块依赖关系并生成Graphviz所需的DOT语言描述文本。
- Graphviz集成模块:负责调用Graphviz工具将DOT文本转换为可视化图片。
- Gradle集成模块:将插件功能集成到Gradle构建流程中,通过Gradle API获取项目相关信息。
获取模块依赖信息
- 使用Gradle的
ProjectDependency
和Configuration
等API。在Gradle构建生命周期的合适阶段(如afterEvaluate
),遍历项目的所有模块及其配置。 - 对于每个模块,获取其
runtimeClasspath
或implementation
等配置的依赖项。示例代码如下:
project.afterEvaluate {
subprojects.forEach { subproject ->
subproject.configurations.forEach { configuration ->
configuration.incoming.dependencies.forEach { dependency ->
if (dependency instanceof ProjectDependency) {
val targetProject = (dependency as ProjectDependency).dependencyProject
println("${subproject.name} depends on ${targetProject.name}")
}
}
}
}
}
与Graphviz集成
- 安装Graphviz:确保运行构建的环境中安装了Graphviz工具,并将其路径添加到系统
PATH
中。 - 生成DOT文本:根据获取的模块依赖信息,按照Graphviz的DOT语言规范生成描述依赖关系的文本。示例代码如下:
val dotBuilder = StringBuilder("digraph {\n")
project.afterEvaluate {
subprojects.forEach { subproject ->
dotBuilder.append("\"${subproject.name}\" [label=\"${subproject.name}\"];\n")
subproject.configurations.forEach { configuration ->
configuration.incoming.dependencies.forEach { dependency ->
if (dependency instanceof ProjectDependency) {
val targetProject = (dependency as ProjectDependency).dependencyProject
dotBuilder.append("\"${subproject.name}\" -> \"${targetProject.name}\";\n")
}
}
}
}
dotBuilder.append("}\n")
val dotFilePath = File(project.buildDir, "dependency_graph.dot")
dotFilePath.writeText(dotBuilder.toString())
}
- 调用Graphviz:使用Java的
ProcessBuilder
调用Graphviz的dot
命令将DOT文本转换为图片(如PNG格式)。示例代码如下:
try {
val dotFilePath = File(project.buildDir, "dependency_graph.dot")
val outputImagePath = File(project.buildDir, "dependency_graph.png")
ProcessBuilder("dot", "-Tpng", dotFilePath.path, "-o", outputImagePath.path)
.inheritIO()
.start()
.waitFor()
} catch (e: Exception) {
e.printStackTrace()
}
完整插件代码示例
import org.gradle.api.Plugin
import org.gradle.api.Project
import java.io.File
class DependencyGraphPlugin : Plugin<Project> {
override fun apply(project: Project) {
project.afterEvaluate {
val dotBuilder = StringBuilder("digraph {\n")
subprojects.forEach { subproject ->
dotBuilder.append("\"${subproject.name}\" [label=\"${subproject.name}\"];\n")
subproject.configurations.forEach { configuration ->
configuration.incoming.dependencies.forEach { dependency ->
if (dependency is ProjectDependency) {
val targetProject = dependency.dependencyProject
dotBuilder.append("\"${subproject.name}\" -> \"${targetProject.name}\";\n")
}
}
}
}
dotBuilder.append("}\n")
val dotFilePath = File(project.buildDir, "dependency_graph.dot")
dotFilePath.writeText(dotBuilder.toString())
try {
val outputImagePath = File(project.buildDir, "dependency_graph.png")
ProcessBuilder("dot", "-Tpng", dotFilePath.path, "-o", outputImagePath.path)
.inheritIO()
.start()
.waitFor()
} catch (e: Exception) {
e.printStackTrace()
}
}
}
}
在buildSrc/src/main/kotlin
目录下创建上述Kotlin文件,然后在项目根目录的settings.gradle.kts
中应用该插件:
plugins {
id("com.example.dependency-graph-plugin") version "1.0" apply true
}
以上就是实现该Kotlin Gradle插件的详细方案及关键代码示例。