资讯专栏INFORMATION COLUMN

自动注入AutoInject:一个通用的代码注入(自动注册)基础库

fasss / 2567人阅读

摘要:通常的处理方式是在主模块硬编码来完成这些事情。那如何不通过在主模块硬编码来完成这些事情解决思路首先,我将问题分解为以下几个小问题问题各业务模块如何对外提供对象业务模块各自新建一个类,实现定义好的接口,通过在接口方法中返回对象。

在组件化的过程中,业务被划分到各自独立的模块,可能会面临以下几点问题:

各业务模块生成的一些索引类需要注册至对应的组件中,比如EventBus索引类的注册,Router索引类的注册。另外,如果各业务模块对外提供的api接口的话,也需要注册api接口。

需要为散落在各个模块中的一些组件提供初始化的时机,有些组件需要在主线程中初始化,有些组件为不阻塞主线程需要在非主线程中初始化。

通常的处理方式是在主模块硬编码来完成这些事情。那如何不通过在主模块硬编码来完成这些事情?

解决思路

首先,我将问题分解为以下几个小问题:

问题1:

各业务模块如何对外提供对象?

业务模块各自新建一个类A,实现定义好的接口IAutoArrow,通过在接口get方法中返回对象。

组件怎么获取对象,并进行注册等相关操作?

为组件新建一个类B,实现定义好的接口IAutoBow,通过在接口shoot方法中获取入参对象T,并进行注册等相关操作。

在什么时候/位置做这件事情?

预先定义一个空方法并在适当时机调用这个空方法。在打包apk时,通过Gradle Transform + ASM,找到类A、类B以及空方法,在空方法内注入一下格式的代码:

A a = new A()
B b = new B()
b.shoot(a.get())

问题2:

如何为各业务模块提供初始化时机?

业务模块各自新建一个类A,实现定义好的接口IAutoBowArrow,通过在接口shoot方法中做初始化事情。

在什么时候/位置做这件事情?

预先定义一个空方法并在适当时机调用这个空方法。在打包apk时,通过Gradle Transform + ASM,找到类A和空方法,在空方法内注入一下格式的代码:

A a = new A()
a.shoot()

设计模型

利用弓把对应型号的箭射向耙子。

箭:对应一种型号

弓:适配对应型号的箭,射向唯一的耙子。

耙子:名称唯一

Usage

在根项目的build.gradle中添加插件依赖:

buildscript {
    ... 
    dependencies {
        ...
        classpath "com.eastwood.tools.plugins:auto-inject:1.0.0"
    }
    
}

继续在模块build.gradle中添加注解库依赖:

dependencies {
    ...
    implementation "com.eastwood.common:auto-inject:1.0.0"
     
}
@AutoArrow

新建一个类,并实现IAutoArrow接口,在get方法中返回对象。例如:

@AutoArrow(model = "eventBusIndex")
public class ModuleBAutoArrow implements IAutoArrow {
 
    @Override
    public SubscriberInfoIndex get() {
        return new ModuleBEventBusIndex();
    }
 
}
@AutoBow

新建一个类,并实现IAutoBow接口,在shoot方法中获取对象并执行相关动作。例如:

@AutoBow(target = "addIndex2EventBus", model = "eventBusIndex", context = true)
public class EventBusAutoBow implements IAutoBow {
 
    private App app;
 
    EventBusAutoBow(Application application) {
        app = (App) application;
    }
 
    @Override
    public void shoot(SubscriberInfoIndex index) {
        app.eventBusBuilder.addIndex(index);
    }
 
}
@AutoTarget

预先定义一个空方法并调用,在方法上标记@AutoTarget,例如:

public class App extends Application {
 
    public EventBusBuilder eventBusBuilder;
 
    @Override
    public void onCreate() {
        super.onCreate();
 
        eventBusBuilder = EventBus.builder();
        // add config to eventBusBuilder
        addIndex2EventBus();
        eventBusBuilder.build();

    }
 
    @AutoTarget
    void addIndex2EventBus() {}

}
@AutoBowArrow

新建一个类,并实现IAutoBowArrow接口,在shoot方法中执行相关动作。

@AutoBowArrow(target = "init")
public class InitAutoBowArrow implements IAutoBowArrow {

    @Override
    public void shoot() {
        // ...
    }

}
将被注入的代码样式

打包成apk后,@AutoTarget对应的方法将会被注入具有固定结构的代码,例如:

@AutoTarget
void addIndex2EventBus() {
    ModuleBAutoArrow moduleBAutoArrow = new ModuleBAutoArrow();
    EventBusAutoBow eventBusAutoBow = new EventBusAutoBow(this);
    eventBusAutoBow.shoot(moduleBAutoArrow.get());
}
 
@AutoTarget
void init() {
    InitAutoBowArrow initAutoBowArrow = new InitAutoBowArrow();
    initAutoBowArrow.shoot();
}
结语

本文并没有详细深入解释Gradle Transform + ASM如何查找到类和方法并注入,源码已上传至github,希望大家自行研究。
github地址:https://github.com/EastWoodYang/AutoInject

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/14246.html

相关文章

  • Android 通用组件自动注册自动初始化解决方案

    摘要:在组件化之前,我们是在通过硬编码来进行注册,在中堆积各个组件的初始化逻辑。分别实现约定的接口,再用注解标记。以上是有关组件注册方面的解决思路,而模块中的组件初始化有点不同,因为其不需要入参。 背景问题 我们在组件化的过程,业务被拆分至独立的Module中,一些公用组件会在各个Module中通过APT生成一些需要被注册至组件中的信息类,比如EventBus生成的Index类。我们这边RN...

    AbnerMing 评论0 收藏0
  • mybatis-plus源码分析之sql注入

    摘要:下面我会详细地从源码的角度分析下文简写成是如何实现自动注入的原理。文件解析器,解析对应的文件信息,并将文件信息注册到中。节点解析器,用于构建节点信息。注册与绑定类,将的类信息与绑定。 微信公众号「后端进阶」,专注后端技术分享:Java、Golang、WEB框架、分布式中间件、服务治理等等。 老司机倾囊相授,带你一路进阶,来不及解释了快上车! mybatis-plus是完全基于myba...

    gougoujiang 评论0 收藏0
  • 模块化(1):基本思路

    摘要:由此可见,模块化思路下构成的复杂系统是由各个可管理的子模块构成的,每个子模块之前相互独立,并通过某种特定的方式进行通信。模块化的好处是显而易见的。其中是最终发布出去的版本,它是对其他模块的整合。一.什么是模块化   什么是模块化呢?有一种定义是:模块化是一种处理复杂系统分解为更好的可管理模块的方式。由此可见,模块化思路下构成的复杂系统是由各个可管理的子模块构成的,每个子模块之前相互独立,并通...

    番茄西红柿 评论0 收藏0
  • 浅谈使用 Vue 构建前端 10w+ 代码单页面应用开发底层

    摘要:其实就是我们开始挂载上去的我们在这里出去,我们就可以在回调里面只处理我们的业务逻辑,而其他如断网超时服务器出错等均通过拦截器进行统一处理。 showImg(https://segmentfault.com/img/remote/1460000015472616?w=845&h=622); 开始之前 随着业务的不断累积,目前我们 ToC 端主要项目,除去 node_modules, bu...

    rickchen 评论0 收藏0
  • 浅谈使用 Vue 构建前端 10w+ 代码单页面应用开发底层

    摘要:其实就是我们开始挂载上去的我们在这里出去,我们就可以在回调里面只处理我们的业务逻辑,而其他如断网超时服务器出错等均通过拦截器进行统一处理。 showImg(https://segmentfault.com/img/remote/1460000015472616?w=845&h=622); 开始之前 随着业务的不断累积,目前我们 ToC 端主要项目,除去 node_modules, bu...

    Backache 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<