【背景】
之前在领英上读到一篇软文,《Managing Software Dependency at Scale》,讲述了领英是如何处理模块之间的依赖解析,以及如何去更好的处理依赖关系以及依赖管理。感觉在一家多产品的公司,在产品有可能相互依赖的情况下,都应该有这么一套系统,来进行依赖关系的管理以及维护。
所以,花费了一天的时间在GitHub上都没有找到可以正常运行的项目之后,决定参照上面的几个现有的实现方式,自己实现一套。
【思考】
首先,简单讲述一下为什么需要这样一个系统?
不知道大家有没有思考,在一个可能有上千个模块/产品的公司,对于模块之间有较多相互依赖的情况,以下问题该如何解决:
- 我们把一个生命周期结束的组件移除之后,会有什么影响?
- 在代码修改之后,我们应该run哪些dependency测试例?
- 在一个已部署的系统中,我们最终要使用哪个version的模块?
- 是否有人使用高危版本的库?
以上问题,其核心原则就是,在所有产品的整个开发周期中,在修改某个依赖的同时,不会对其他产品造成任何影响。
【如何保存依赖关系】
之前的时候,考虑过使用键值对数据库和非关系型数据库去保存相关的依赖,但是效果都不理想,最后选用了图数据库(Neo4J).
这样做有三个好处:
- 对于任意模块,不论其是否依赖其他模块,或是被其他模块依赖,都可以很直观得在数据库中体现;
- 对于任意模块,其依赖的下级模块和上级模块可以快速地导出;
- 对于跨级依赖可以有更好的体现。
【设计】
代码结构如下:
在Model中,Dependency映射pom文件中的dependency,Project映射产品,Neo4jConn映射数据库信息。
Service中,GraphBuilder主要处理产品以及模块之间的相互依赖关系,Neo4JHandler主要处理与数据库相关的具体操作。
Util里面,Finder继承SimpleFileVisitor,处理一些路径的匹配工作,PomFileFinder利用Finder,寻找所有的pom文件并返回列表,XMLConverter利用javax.xml的工具类处理具体的xml文件。
DependencyManager作为整个程序的入口,对外提供服务。
【使用】
首先在工程目录下执行mvn clean install/package打包;
然后进入target目录下执行:
java -jar dependency-manager-0.0.1-SNAPSHOT-jar-with-dependencies.jar D:/workspace/World bolt://localhost:7687 neo4j neo4j Module org.spring*
第一个参数指定pom文件路径(默认递归到20层,超过无法识别到);
第二个参数指定数据库的url,第三个参数指定数据库用户名,第四个参数指定数据库密码;
第五个参数指定需要导出依赖关系的是产品还是模块,如果指定模块,会将所有满足条件的模块全部导出,如果只指定产品,则只导出所有产品之间的依赖关系。
第六个参数指定模块需要满足的条件,可以指定前缀,中缀,后缀,如spring*,指所有以spring开头的包,这种方式可以去掉一些我们不关注的包,比如org相关的,spring框架相关的,可以大大降低我们的工作量。
当然,你也可以直接执行:
java -jar dependency-manager-0.0.1-SNAPSHOT-jar-with-dependencies.jar
命令来获取帮助。
如图所示则执行成功:
【结果】
执行结果可以在Neo4J中查看:
红色为产品,褐色为模块。
【优化】
当然了,这只是一个小应用,还有很大的发展空间,之后会有如下几个改进:
- Dependency Manager UI可视化,可以直接将结果通过页面的方式展示给用户;
- 通过自动化的方式更新依赖关系;
- 根据模块使用情况自动发出循环依赖以及废弃库使用的警告;
- 可以跨平台使用,不局限于Maven管理的Java项目。
当然,也希望有同样想法的小伙伴可以提提设计上的意见,或者阅读过源码之后有改进的思路给到,都不胜荣幸。
【获取】
GitHub地址:https://github.com/liufarui/dependency-manager