我正在参加「启航计划」
1、背景
近期在探究项目端架构晋级,遇到不少前史遗留问题,比较典型的便是模块耦合、动态路由装备表冗余。一起,也在探究如何运用智能战略提供更好的根底体验,用好的技术计划做一些既要又要还要(老板们都是这么想)的工作。
无意看到了 TheRouter
,发现它的规划思路能处理目前项目所面对的问题,作者对端侧动态才能的发展方向上与我的思路不约而同(端+云+智能战略),看完还是有点小兴奋。
于是,立马把代码拉下来看看,结果异常了~
2、问题
在拉取master
分支并运转后,发现如下问题:
3、分析
3-1 外表原因
从错误提示上看异常类在/build/generated/source/kapt/debug/
文件中,说明出问题的类是kapt
主动生成的代码。
再看看Test3#createTest5
这个函数实现,基本能确认:kapt
主动生成的类,在调用Test3#createTest5
时少了一个参数。
3-2 APT 逻辑
1、首先需求找到生成问题类的函数, 经过查找确认TheRouterAnnotationProcessor#genJavaFile
中生存了问题类(以下逻辑有删减):
private fun genJavaFile(
pageList: ArrayList<ServiceProviderItem>,
flowTaskList: MutableList<FlowTaskItem>,
actionInterceptorList: MutableList<ActionInterceptorItem>
) {
var ps: PrintStream? = null
try {
......
ps.println(") {")
ps.println("\t\t\t//type verification during compilation prevents the actual return type of the method from mismatching with the return type declared by the annotation")
if (serviceProviderItem.isMethod) {
ps.print(String.format("\t\t\t%s returnType = %s.%s(", serviceProviderItem.returnType,serviceProviderItem.className,serviceProviderItem.methodName))
}
......
for (count in serviceProviderItem.params.indices) {
if (!serviceProviderItem.params[count].trim { it <= ' ' }.isEmpty()) {
//参数强转
ps.print(String.format(Locale.getDefault(),"(%s) params[%d]",serviceProviderItem.params[count],count))
if (count != serviceProviderItem.params.size - 1) {
ps.print(", ")
}
}
}
ps.println(");")
ps.println("\t\t\tobj = (T) returnType;")
ps.print("\t\t} else ")
}
...
}
从上述逻辑能够了解到:serviceProviderItem.params
便是终究的参数表。
2、再断点调试发现createTest5
的参数理论上有两个:String
和 Context
,然而serviceProviderItem.params
中却只有一个, 所以问题基本能定位是serviceProviderItem.params
的赋值问题了。
3、serviceProviderItem.params
是在这个函数TheRouterAnnotationProcessor#handleMethodServiceProviderItem
中赋值的,经过解析注解中的信息赋值给 params 。
依照代码逻辑,这儿 temp
的值应该是“@com.therouter.inject.ServiceProvider(params=java.lang.String,android.content.Context”
可是这儿实际值是"@com.therouter.inject.ServiceProvider(params=java.lang.String"
,所以这儿看起来是本地代码与项目代码不一致。
再看 commit 记录这个问题在之前涛哥有专门修过,少了一个空格符。
所以本地代码应该是 OK 的。
4、问题处理
1、把 apt 模块改成本地依赖再编译确实能够了,或许换成最新的版本也是OK的。
问题是处理了,可是看注解的解析过程还是比较费劲且不太优雅。
5、优化一下
1、再看看解析上能怎么能优化一下,梳理一下TheRouterAnnotationProcessor#handleMethodServiceProviderItem
的中心逻辑。
运用了比较多index
和length
,解析逻辑相对杂乱不太好理解。
2、回到要解析的字符串———“@com.therouter.inject.ServiceProvider(params=java.lang.String,android.content.Context,returnType=com.therouter.inject.ServiceProvider)”
,其实能够用正则直接找出对应的 Key-Value 赋值即可,能够添加代码可读性,一起解析逻辑复用度也相对高些:
6、提个PR
github.com/HuolalaTech…
7、最终一点主张
最终,给 TheRouter 所提的动态路由才能提点主张:动态路由除了重视动态才能外,前期也主张做好装备热度盯梢。跟着业务的迭代,假如没有对应的热度计算,后期大量的冗余装备会对装备的运转加载稳定性造成负面影响,一起过大的路由表会延伸匹配时刻进而影响页面翻开速度等。一起,路由自身能够理解为APP运转的中枢神经,跟着装备的增多,后期迁移、改动或替换的风险较高,所以应想办法在前期做好计算办理,防止装备冗余。