登录 立即注册
安币:

安卓巴士 - 安卓开发 - Android开发 - 安卓 - 移动互联网门户

演讲实录——仓库依赖管理器 [复制链接]

2019-5-9 10:52
九霄逆鳞 阅读:153 评论:0 赞:0
Tag:  

本文来自2019安卓巴士开发者大会现场实录,由于录入匆忙,内容可能存在偏差,欢迎大家扫描文末二维码查看现场实录视频和下载大会完整PPT。讲师:王世昌


大家上午好,今天我分享的主题是关于Android工程效率方面的,仓库依赖管理器。

 

个人简介


我先介绍下,我常用的网络ID是墨镜猫和JackyWang,我在github的star,java方面的话有四千七百多,总的star在一万两千多,在深圳java分类排名应该可以排到前三。我之前在滴滴和乐视工作过,现在在TCL·雷鸟。

 


开源贡献


给大家说下我这几年对开源社区的贡献,原创的项目有7个,贡献的代码有39.4w行,和8个国家12个地区的开发者一起维护其中的3个项目,其中两个仓库在各自的类别里面排到了前三。


我是从14年开始做开源,一直到现在,中间换了一次ID,所以你们看到我的账号是从16年开始的。我14年开始做开源的时候,当时是做了一个小项目放了上去,后来就过了一年多时间,突然有一天有一个爱尔兰的程序员给我发邮件,说你做的这个开源项目还可以,正好我们这有一个可以合作的项目,后来我们就聊了聊,大概意思就是想让我根据我那个开源项目给他们做下定制,价钱大概是三千美金。这件事对我触动还是非常大的,开源社区就像你和世界上其他人沟通的一个窗口一样,可以把你和任意位置的人连接起来,并产生价值。从那之后就一直做开源到现在,收获的远比我之前想象的要多得多,认识了很多有趣的人、见识到了世界级的项目是什么样的还认识了像Facebook、微软这种级别企业的Hr,开源社区的价值还是非常大的。

 


仓库维护的痛点


接下来说下依赖管理器,我们先看下这张图,一个常见的依赖关系图,这个就像一个倒立的大树一样,每一个叶子都是一个仓库,树根就是主客户端,树里面每个叶子之间也有很复杂的依赖关系,如果这个时候监控这个叶子出现了问题,就像这样,依赖他的上面的十几个叶子都会受到影响。


假如你改动了一个仓库,比如这个监控仓库,受影响的有依赖他的十几个仓库,就是这个图里面红色箭头指的地方,每个受影响的仓库都得升级到修复过后的版本,去一一验证,而且这个过程非常容易反复,比如你修复了一个问题,对日志生效了,但对图像又产生了问题,再修复,再发版本,还要再把十几个仓库升级再去验证,不停的重复这个过程,浪费很多时间。

 

那怎么去提升仓库的维护效率,减少验证的次数?

 


解决方案


那有没有更彻底更高效的方式,在主工程里面把十几个受影响的仓库一次性验证完,只验证一次行不行。


那怎么才能实现只验证一次呢?就是把受影响的线上仓库,转为本地的可修改可编辑的源码仓库。比如我现在要修复监控仓库,我把线上监控仓库转为本地源码仓库。

 

上面受影响的十几个仓库依赖的都是本地的源码仓库,而不是线上地址。这样有问题只需要在本地监控仓库修复,改完后对依赖监控的十几个仓库同时有效。这样就可以了,对吧?

 

那关键是怎么把线上仓库转为源码仓库,最原始的方式就是把线上的地址在工程里面注释掉,把源码工程include进来。这种方式对于较复杂的项目来说,成本太高,也不可维护。

 

我们是希望只需要一个开关,就可以灵活的切换线上线下依赖。打开就是本地源码工程,关闭就是线上依赖。我们看下该怎么去实现。

 


关键点


配置语言怎么选?


首先配置该怎么选?配置可选的方式有很多种,json、xml、dsl或者其他的配置语言。json、xml在结构化扩展方面还是挺强的,但是一旦结构变得复杂,可读性就会比较差,我们看下这个对比图,左边是DSL,右边是同样结构的JSON描述,很显然json阅读起来还是挺困难的,关于DSL有一句话挺有意思,“你以为这是一句话,其实这是一段脚本”

 

动态加载DSL


解析json和xml其实都比较简单,就是读文件就好了,但是对于dsl这种怎么办?

关于dsl文件其实本质上还是一个脚本,关于dsl有句话也是这么说的,你以为这是一句话 其实这是一个脚本。所以我们首先还是去动态加载这个脚本,在groovy里面提供了groovyshell,可以加载任意的groovy脚本,调用evaluate方法就可以加载独立的groovy 脚本,evaluate方法可以接受脚本字符、文件、Uri都可以。加载脚本之后,我们还需要拿到我们在dsl里面配置的信息,就是pod里面的东西,就是在定义脚本的地方,定义一个接受闭包的函数,函数名为pod,当groovyshell去加载脚本的时候,遇到pod配置,就会被这个函数接收,然后就可以把我们在项目中配置的dsl信息拿到。


简单来讲,就是通过groovyshell去执行这个dsl脚本,每一个pod可以看成是一个函数调用,括号里面的就是传进去的参数值,调用这个函数的声明就是这样写,然后我们就可以拿到我们在项目中的配置。这样就完成了dsl的动态加载。

 


动态包含任意地址本地仓库


首先,包含进来的项目才能依赖,所以第一步我们需要能动态的include本地任意路径的源码模块。在gradle 初始化阶段加载settings.gradle 时候,去apply我们的插件,这个时候可以拿到settings实例,这个和配置阶段拿到的project是不一样的,settings里面有个很重要的接口include,include里面填上我们配置的项目名称就可以了,和我们直接在settings.gradle里面直接写include是一样的,不一样的是我们这个是动态的。然后需要对我们刚刚include进去的project指定路径,settings里面可以通过project拿到我们指定名称的项目描述,在这个描述里面可以配置路径,任意的本地路径。

 


动态去除线上、添加本地仓库


经过之前的准备,终于到了最后一步,按照我们的配置去修改这个依赖关系了。

第一步,怎么把线上的依赖去除掉?在gradle配置阶段,我们每一个project都会apply我们的插件,apply的时候我们就可以拿到当前project实例,这和上面那个初始化阶段是不一样的,那个拿的是settings实例,我们通过project里面的configuration,可以去配置我们需要去除的线上依赖信息,configuration的exclude接口接收的是一个map,在这个map里配置我们在DSL里面配置的name和group就可以了。


下一步,我们需要把我们之前include进来的project,添加到我们的项目中去,通过我们当前的project实例,拿到当前工程的依赖关系,这个依赖是一个DependencyHandler,这个handler使用来描述依赖关系的,通过handler的add接口就可以把我们的本地仓库依赖动态添加进去,add接口接收buildtype和project实例,buildtype就是我们平常依赖使用的compile apiimplementation这些东西。

 

总的来说,通过配置信息把我们需要去除的依赖填进去,通过DependencyHandler把我们本地的project依赖添加进去,这样就实现了动态替换,线上依赖切换为线下依赖。

 


流程


然后我们看下实现流程,大概分为两个流程,初始化阶段和配置阶段,在gradle初始化阶段会先解析dsl,然后把需要调试的模块include 进来,在这中间可以做很多事情,比如我想依赖的是问题修复的分支,那就配置下分支名称就可以,执行自定义的hook命令。在gradle配置阶段,根据我们dsl的配置信息,去在依赖树里去寻找需要替换的节点,就像一个毛毛虫一样,去反复的去查找需要替换的叶子,找到后发现需要替换,就把需要调试的线上模块替换成本地的模块。因为仓库变多后,dsl的配置变多,所以我这还有一个辅助生成dsl的任务,他会自动扫描当前哪些是我们可以调试的,比如我们内部的maven仓库,把依赖树的信息转换为dsl,这个功能目前还在测试阶段,还没开源出来。

 

总的来说,大致分为两个流程,初始化阶段先把工程include进来,配置阶段再把线上依赖去除,添加本地依赖。

 

我们回顾下,这个插件解决的是什么问题?解决的是maven仓库依赖复杂,修复的过程繁琐。那是怎么去做的?用DSL配置仓库的基本信息,在gradle初始化阶段插件动态include仓库的源码工程,在配置阶段插件动态去除线上依赖、动态添加本地依赖,这样就做到了动态替换的效果,提升我们的维护效率,对吧。

 


效果


我们看下效果,首先我们现在的主工程是monitor sample,在项目根目录配置一个dsl文件,内容的话就是这样,每一个仓库对应一个pod,pod里面有开关,项目的name和group就是对应一个线上地址(图里面线上地址和pod对应)然后把需要调试的模块打开,重新sync工程,这时候上面就会出现本地的源码仓库,然后线上仓库就会被转为线下源码仓库,这时候可以对需要修复的仓库编辑、调试、验证功能、发布,只需要验证一次,节省很多时间。

 

我在举一个实际的例子吧,比如说我们现在有一个30人的团队,这三十人分成6个业务线,每个业务线都依赖了我们底层的网络库,网络库针对每个业务线都有相应的缓存及加密策略。如果这时候需要修改网络库的缓存策略,先在网络库的源工程里面去做修改,然后再发布到内网的maven服务器,然后再升级各个业务线的网络库版本号,再去验证,如果修改的功能不能满足需求,还得重新走上面的流程,浪费很多时间。那把网络库的依赖通过插件转为本地依赖,是不是就可以一次验证完了?对各个业务线验证完成之后再发布,不会重复的去走发布-验证这个流程,节省很多时间。


 

今天分享基本就是这些,然后这些是我的联系方式github、个人网站和我的微信,大家如果有疑问在交流群里或微信问我都可以,谢谢大家。





现场PPT分享:

      关注【安卓巴士Android开发者门户】公众号,后台回复“420”获取讲师完整PPT。


大会现场视频小程序:




欢迎前往安卓巴士博客区投稿,技术成长于分享

期待巴友留言,共同探讨学习


分享到:
我来说两句
facelist
您需要登录后才可以评论 登录 | 立即注册
所有评论(0)

站长推荐

通过邮件订阅最新安卓weekly信息
上一条 /4 下一条

下载安卓巴士客户端

全国最大的安卓开发者社区

广告投放| 广东互联网违法和不良信息举报中心|中国互联网举报中心|下载客户端|申请友链|手机版|站点统计|安卓巴士 ( 粤ICP备15117877号 )

返回顶部