关于ARouter的思考

前言

网络上给大家介绍如何使用ARouter的很多,对ARouter进行分析的也很多,这篇文章更多的是记录我自己的理解,谈谈它的设计思想及解决项目中的什么问题(如果这篇文章能给他人带来哪怕一点帮助,那它也是有价值的----来自一个无证程序员)

ARouter的根基--------APT

很多框架或者现在流行的90%的框架都离不开apt(annotation process tool),那么他到底是个什么东西

它是一个帮助程序在编译期进行部分程序或者代码生成的工具,它的作用就像是jdk 动态代理 只不过动态代理是在后期运行期进行字节码的生成,而apt的文件生成是在javac这一时刻,所以在jvm里面更准确的定位叫"编译器的前端"(这里不会更多的提及后期的JIT)。回想起来现在的框架都是在原有java的基础上扩散开来的,就说编译期生成文件吧其实javac才是编译期的鼻祖,同时aop的思想更多的是jdk的动态代理,ioc的思想更多是来自java spi...(至于是不是真的源自于java都不重要)

javac 都做了什么动作?首先javac 的程序是java写的,在openjdk里面可以看到javac 的过程源码

1 插入式注解处理过程

2 词法语法分析

3 分析及字节码生成

OpenJDK ----langtools:

com.sun.tools.javac.main.JavaCompile

查看compile函数:

public void compile(List sourceFileObjects,List classnames,Iterable processors)

throws IOException// TODO: temp, from JavacProcessingEnvironment

{

    if (processors !=null && processors.iterator().hasNext())

        explicitAnnotationProcessingRequested =true;

        // as a JavaCompiler can only be used once, throw an exception if

        // it has been used before.

        if (hasBeenUsed)

                throw new AssertionError("attempt to reuse JavaCompiler");

        hasBeenUsed =true;

        start_msec =now();

try {

        initProcessAnnotations(processors);

        // These method calls must be chained to avoid memory leaks

        delegateCompiler = processAnnotations(enterTrees(stopIfError(CompileState.PARSE,parseFiles(sourceFileObjects),classnames);

        delegateCompiler.realCompile();

        delegateCompiler.close();

        elapsed_msec =delegateCompiler.elapsed_msec;

        }catch (Abort ex) {

            if (devVerbose)

                ex.printStackTrace();

        }finally {

            if (procEnvImpl !=null)

                    procEnvImpl.close();

            }

        }

initProcessAnnotations(processors); 插入注解处理器---->这里是不是想到android里面要自己实现AbstractProcessor, 

里面包含对应函数:

public synchronized void init(ProcessingEnvironment processingEnv)

public abstract boolean process(Set annotations,RoundEnvironment roundEnv);

接下来processAnnotations  执行真正的注解处理,parseFiles执行词法语法分析

delegateCompiler.realCompile();这里realCompile 是我自己源码里修改过的函数名(原函数名:compile2()) 

void realCompile() {

try {

switch (compilePolicy) {

case ATTR_ONLY:

attribute(todo);

break;

case CHECK_ONLY:

flow(attribute(todo));

break;

case SIMPLE:

generate(desugar(flow(attribute(todo))));

break;

case BY_FILE: {

Queue>> q =todo.groupByFile();

while (!q.isEmpty() && !shouldStop(CompileState.ATTR)) {

generate(desugar(flow(attribute(q.remove()))));

}

}

break;

case BY_TODO:

while (!todo.isEmpty())

generate(desugar(flow(attribute(todo.remove()))));

break;

default:

assert false:"unknown compile policy";

}

}catch (Abort ex) {

if (devVerbose)

ex.printStackTrace();

}

if (verbose) {

elapsed_msec =elapsed(start_msec);

printVerbose("total", Long.toString(elapsed_msec));

}

reportDeferredDiagnostics();

if (!log.hasDiagnosticListener()) {

printCount("error", errorCount());

printCount("warn", warningCount());

}

}

其中switch 是BY_TODO时 进行generate动作。

已经清楚了javac编译的过程,之所以在android里面使用apt这么流畅不过是google真对processor的过程做了封装.

apt技术的实现这样看来不难,最主要的是在知道利用apt技术来解决项目中的问题,举一个例子:

最初项目里面if else很多,都会尝试使用factory模式来尝试优化重构这种现状,if else在某种意义上是取消不掉的。

class Animal 

class Person

class Dog

class Factory{

    Animal create(String flag){

                if(flag.equals("xxxx")) return Person();

               else if(flag.equals("ssss")) return Dog();

               else if(xxxxxxxx)

               .......

               else

}

如果有新的Animal子类对象A产生,除了编写A对象逻辑之外还是要修改 Factory对象,这样的话在某种程度打破了ocp原则,引入了新的代码就有引入新bug的风险。我认为这个时候就可以尝试使用Apt 通过注解,在编译阶段 搜集被注解标记的java,经过自己编写的procssor 组装自己的factory实现,代替手动修改Factory。

结构可能如下:

@Animal

class Person{}

@Animal

class Dog{}

class MyProcessor extends AbstractProcessor{

    init(){xxxxx}

    process(xxxxx){

               生成MyFactory逻辑

    }

}

新增的A类 只需要使用@Animal注解标记即可

@Animal

class A{}

以上在经历过  前端编译 之后自然就会把A对象的判断添加到MyFactory的逻辑判断里面

截止到这里为止还是没有提到ARouter的使用(文章开头已经提到了 这不是讲解ARouter使用及原理的文章,而是我在阅读ARouter源码之后的一些思考)。如果只在Android的一个module或者一个app里面确实对设计或者代码进行了优化(最初的app 也都是从小工程衍生)随着业务的扩增,整个app就伴随模块化,组件化,插件化。。。。

那么针对模块化、组件化,ARouter做了一个很巧妙处理(与其说ARouter不如说java) java的先知们使用了getOptions(Map<String,String>)来处理这个问题(不得不佩服java的伟大设计者)。

在ARouter之前我个人确实写了一个类似ARouter的框架但是就在我刚要完成的时候却又实现不了,代码的生成以及模块化代码生成的问题都已经解决了但是在却最后进行合并java的时候除了问题,刚开始的时候想尝试使用gradle在合并编译阶段进行搜索文件,理论上是可行的要注意的一个问题无非就是gradle的后期兼容性问题,然而随着现实中项目的情况就暂行搁置以至于到了后来ARouter的出现也确实让我很自责(我也曾自我反省是不是做什么事都是在最后即将完成的时候总是松懈,高考是这样,自己的很多想法也是这样,不确定这算不算我人性弱点中的一部分),后来我也就是翻看了ARouter的源码,主要是想看看他的设计者是如何处理这个问题的,当看到在

ARouter.init(){

    xxxxx

    ClassUtils.getFileNameByPackageName(xxxx,xxx)

    xxxxx

}

Set<String> getFileNameByPackageName(){

        for(xxxxx){

                DexFile file = new DexFile(path);        

               针对 file下的文件根据APT生成的文件名规则进行查找,并放入WareHouse缓存中

    }

}

看到了关键了就是DexFile这个操作,而不是想我的想法一样使用gradle在编译阶段进行合并收集这里很佩服ARouter的设计者,在事后我进行反思思维的局限让我根本没有把想法结合到Android这里没有想到使用Android本身的机制来解决问题,或者说我偏离了方向(当然不知道ARouter在阿里进行设计的时候是一群人还是一个人,像我一个人和他人的沟通较少又受限于自己的想法)

给自己以后的建议:有想法还是要和他人分享,让自己广角看设计(非兵不利,战不善,弊在视角)

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,290评论 6 491
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,107评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,872评论 0 347
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,415评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,453评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,784评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,927评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,691评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,137评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,472评论 2 326
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,622评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,289评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,887评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,741评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,977评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,316评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,490评论 2 348

推荐阅读更多精彩内容