在组件化的过程中,业务被划分到各自独立的模块,可能会面临以下几点问题:
- 各业务模块生成的一些索引类需要注册至对应的组件中,比如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<SubscriberInfoIndex> {
@Override
public SubscriberInfoIndex get() {
return new ModuleBEventBusIndex();
}
}
@AutoBow
新建一个类,并实现IAutoBow接口,在shoot方法中获取对象并执行相关动作。例如:
@AutoBow(target = "addIndex2EventBus", model = "eventBusIndex", context = true)
public class EventBusAutoBow implements IAutoBow<SubscriberInfoIndex> {
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