Android滴滴路由框架DRouter原理解析_could not generate d_router table(2)

调用DRouter.init(app)后的时序图如下:

默认是在子线程实现路由表加载,不影响主线程。

public static void checkAndLoad(final String app, boolean async) {
if (!loadRecord.contains(app)) {
// 双重校验锁
synchronized (RouterStore.class) {
if (!loadRecord.contains(app)) {
loadRecord.add(app);
if (!async) {
Log.d(RouterLogger.CORE_TAG, “DRouter start load router table sync”);
load(app);
} else {
new Thread(“drouter-table-thread”) {
@Override
public void run() {
Log.d(RouterLogger.CORE_TAG, “DRouter start load router table in drouter-table-thread”);
load(app);
}
}.start();
}
}
}
}
}

最终走到了RouterLoader的load方法来加载路由表到一个map中,仔细看它的引入路径是com.didi.drouter.loader.host.RouterLoader,是不存在于源码中的,因为它是编译的时候生成的,位置位于app/build/intermediates/transforms/DRouter/dev/debug/…/com/didi/drouter/loader/host/RouterLoader。

public class RouterLoader extends MetaLoader {
@Override
public void load(Map var1) {
var1.put(“@@$$/browse/BrowseActivity”, RouterMeta.build(RouterMeta.ACTIVITY).assembleRouter(“”, “”, “/browse/BrowseActivity”, “com.example.demo.browse.BrowseActivity”, (IRouterProxy)null, (Class[])null, (String[])null, 0, 0, false));
}

public RouterLoader() {
}
}

public abstract class MetaLoader {

public abstract void load(Map<?, ?> data);

// for regex router
protected void put(String uri, RouterMeta meta, Map<String, Map<String, RouterMeta>> data) {
Map<String, RouterMeta> map = data.get(RouterStore.REGEX_ROUTER);
if (map == null) {
map = new ConcurrentHashMap<>();
data.put(RouterStore.REGEX_ROUTER, map);
}
map.put(uri, meta);
}

// for service
protected void put(Class<?> clz, RouterMeta meta, Map

不难猜出其是在编译期加了一个transform,生成RouterLoader类时加入了load方法的具体实现,具体来说是javaassit API+Gradle Transform,所以去看看drouter-plugin在编译期做了什么。

2.编译期transform

直接看时序图。

创建了一个RouterPlugin,并且注册了一个Gradle Transform。

class RouterPlugin implements Plugin {

@Override
void apply(Project project) {

project.android.registerTransform(new TransformProxy(project))
}
}

class TransformProxy extends Transform {
@Override
void transform(TransformInvocation invocation) throws TransformException, InterruptedException, IOException {
String pluginVersion = ProxyUtil.getPluginVersion(invocation)
if (pluginVersion != null) {

if (pluginJar.exists()) {
URLClassLoader newLoader = new URLClassLoader([pluginJar.toURI().toURL()] as URL[], getClass().classLoader)
Class<?> transformClass = newLoader.loadClass(“com.didi.drouter.plugin.RouterTransform”)
ClassLoader threadLoader = Thread.currentThread().getContextClassLoader()
// 1.设置URLClassLoader
Thread.currentThread().setContextClassLoader(newLoader)
Constructor constructor = transformClass.getConstructor(Project.class)
// 2.反射创建一个RouterTransform
Transform transform = (Transform) constructor.newInstance(project)
transform.transform(invocation)
Thread.currentThread().setContextClassLoader(threadLoader)
return
} else {
ProxyUtil.Logger.e(“Error: there is no drouter-plugin jar”)
}
}
}
}

注释2处反射创建一个com.didi.drouter.plugin.RouterTransform对象,并执行其transform方法,此处真正处理transform逻辑,它的位置位于drouter-plugin模块。

class RouterTransform extends Transform {
@Override
void transform(TransformInvocation invocation) throws TransformException, InterruptedException, IOException {

// 1.创建一个DRouterTable目录
File dest = invocation.outputProvider.getContentLocation(“DRouterTable”, TransformManager.CONTENT_CLASS,
ImmutableSet.of(QualifiedContent.Scope.PROJECT), Format.DIRECTORY)
// 2.执行RouterTask
(new RouterTask(project, compilePath, cachePathSet, useCache, dest, tmpDir, setting, isWindow)).run()
FileUtils.writeLines(cacheFile, cachePathSet)
Logger.v(“Link: https://github.com/didi/DRouter”)
Logger.v("DRouterTask done, time used: " + (System.currentTimeMillis() - timeStart) / 1000f + “s”)
}
}

注释2处new了一个RouterTask对象,并执行其run方法,之后的log输出就是平时编译能看到的信息,表示transform的耗时。

public class RouterTask {
void run() {
StoreUtil.clear();
JarUtils.printVersion(project, compileClassPath);
pool = new ClassPool();
// 1.创建ClassClassify
classClassify = new ClassClassify(pool, setting);
startExecute();
}

private void startExecute() {
try {

// 2.执行ClassClassify的generatorRouter
classClassify.generatorRouter(routerDir);
Logger.d("generator router table used: " + (System.currentTimeMillis() - timeStart) + “ms”);
Logger.v("scan class size: " + count.get() + " | router class size: " + cachePathSet.size());
} catch (Exception e) {
JarUtils.check(e);
throw new GradleException(“Could not generate d_router table\n” + e.getMessage(), e);
} finally {
executor.shutdown();
FileUtils.deleteQuietly(wTmpDir);
}
}
}

重点在于ClassClassify这个类,其generatorRouter方法便是最终处理生成路由表的逻辑。

public class ClassClassify {
private List classifies = new ArrayList<>();

public ClassClassify(ClassPool pool, RouterSetting.Parse setting) {
classifies.add(new RouterCollect(pool, setting));
classifies.add(new ServiceCollect(pool, setting));
classifies.add(new InterceptorCollect(pool, setting));
}

public void generatorRouter(File routerDir) throws Exception {
for (int i = 0; i < classifies.size(); i++) {
AbsRouterCollect cf = classifies.get(i);
cf.generate(routerDir);
}
}
}

构造函数处添加了RouterCollect/ServiceCollect/InterceptorCollect,最终执行的是他们的generate方法,分别处理路由表、service、拦截器,我们只看路由表的。

class RouterCollect extends AbsRouterCollect {
@Override
public void generate(File routerDir) throws Exception {
// 1.创建RouterLoader类
CtClass ctClass = pool.makeClass(getPackageName() + “.RouterLoader”);
CtClass superClass = pool.get(“com.didi.drouter.store.MetaLoader”);
ctClass.setSuperclass(superClass);

StringBuilder builder = new StringBuilder();
builder.append(“public void load(java.util.Map data) {\n”);
for (CtClass routerCc : routerClass.values()) {
try {
// 处理注解、class类型等逻辑

StringBuilder metaBuilder = new StringBuilder();
metaBuilder.append(“com.didi.drouter.store.RouterMeta.build(”);
metaBuilder.append(type);
metaBuilder.append(“).assembleRouter(”);
metaBuilder.append(“”“).append(schemeValue).append(”“”);
metaBuilder.append(“,”);
metaBuilder.append(“”“).append(hostValue).append(”“”);
metaBuilder.append(“,”);
metaBuilder.append(“”“).append(pathValue).append(”“”);
metaBuilder.append(“,”);
if (“com.didi.drouter.store.RouterMeta.ACTIVITY”.equals(type)) {
if (!setting.isUseActivityRouterClass()) {
metaBuilder.append(“”“).append(routerCc.getName()).append(”“”);
} else {
metaBuilder.append(routerCc.getName()).append(“.class”);
}
} else {
metaBuilder.append(routerCc.getName()).append(“.class”);
}

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数HarmonyOS鸿蒙开发工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年HarmonyOS鸿蒙开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上HarmonyOS鸿蒙开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新

如果你觉得这些内容对你有帮助,可以添加VX:vip204888 (备注鸿蒙获取)
img

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新

如果你觉得这些内容对你有帮助,可以添加VX:vip204888 (备注鸿蒙获取)
[外链图片转存中…(img-caDr3iZH-1712647982885)]

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 7
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值