Android之旅 -- ARouter 源碼分析(一) 主要介紹了 ARouter 啟動 activity 的基本原理.
這篇我們來看下在編譯期 arouter-compiler 都做了哪些事情
介紹
大概梳理一下 arouter-compiler, 先查看 build.gradle
// build.gradle
// 這里要注意, 不能用 com.android.library, 因為對 annotation 的處理需要用的javax 包下的類, android sdk是沒有的.
apply plugin: 'java'
...
dependencies {
// 這里依賴的不是源碼的module
compile 'com.alibaba:arouter-annotation:1.0.3'
// 這個是自動生成 META-INF 配置 Processor 內容的
compile 'com.google.auto.service:auto-service:1.0-rc2'
// 用來生成代碼的, 比拼字符串生成源碼要高大上一些
compile 'com.squareup:javapoet:1.7.0'
...
可以看到 arouter-compiler 通過 自動配置的 Processor, 查找聲明了 arouter-annotation 里定義的 annotation, 然后根據 annotation 的配置使用 javapoet 生成輔助注入的代碼, 達到在開發中可以不用實際依賴一些類, 達到模塊或者組件之間的解耦.
arouter-compiler 源碼分析
arouter-compiler 有三個 Processor
AutowiredProcessor -- 處理 @Autowired
InterceptorProcessor -- 處理 @Interceptor
RouteProcessor -- 處理 @Autowired, Route
- 先分析 RouteProcessor 的工作原理, 先看看 init 方法里初始化做了什么
// RouteProcessor.java
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
// 用來生成代碼的 Filer 對象
mFiler = processingEnv.getFiler();
// 數據類型和類的描述
types = processingEnv.getTypeUtils(); // Get type utils.
elements = processingEnv.getElementUtils(); // Get class meta.
typeUtils = new TypeUtils(types, elements);
...
// module name, 使用 arouter-compiler 的module 都要配置在build.gradle, 否則拋出 exception
moduleName = options.get(KEY_MODULE_NAME);
// 獲取 com.alibaba.android.arouter.facade.template.IProvider 的 TypeMirror 對象
iProvider = elements.getTypeElement(Consts.IPROVIDER).asType();
}
接下來我們進入核心的 process 方法, init, process 這兩個方法都是 Processor 自動調用的
// RouteProcessor.java
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
...
Set<? extends Element> routeElements = roundEnv.getElementsAnnotatedWith(Route.class);
this.parseRoutes(routeElements);
...
}
主要邏輯都在 parseRoutes 這個方法中, 繼續查看下去, 這個方法寫的有點長...
private void parseRoutes(Set<? extends Element> routeElements) throws IOException {
// 創建參數類型 Map<String, Class<? extends IRouteGroup>>
ParameterizedTypeName inputMapTypeOfRoot = ParameterizedTypeName.get(
ClassName.get(Map.class),
ClassName.get(String.class),
ParameterizedTypeName.get(
ClassName.get(Class.class),
WildcardTypeName.subtypeOf(ClassName.get(type_IRouteGroup))
)
);
// 創建參數類型 Map<String, RouteMeta>
ParameterizedTypeName inputMapTypeOfGroup = ParameterizedTypeName.get(
ClassName.get(Map.class),
ClassName.get(String.class),
ClassName.get(RouteMeta.class)
);
// 創建方法參數 routes, atlas, providers
ParameterSpec rootParamSpec = ParameterSpec.builder(inputMapTypeOfRoot, "routes").build();
ParameterSpec groupParamSpec = ParameterSpec.builder(inputMapTypeOfGroup, "atlas").build();
ParameterSpec providerParamSpec = ParameterSpec.builder(inputMapTypeOfGroup, "providers").build();
// 聲明 public void loadInto(Map<String, Class<? extends IRouteGroup>> routes)
MethodSpec.Builder loadIntoMethodOfRootBuilder = MethodSpec.methodBuilder(METHOD_LOAD_INTO)
.addAnnotation(Override.class)
.addModifiers(PUBLIC)
.addParameter(rootParamSpec);
// 遍歷所有申明的 @Route
for (Element element : routeElements) {
// 取得 class 的類型描述
TypeMirror tm = element.asType();
// 取得@Route注解的實例
Route route = element.getAnnotation(Route.class);
RouteMeta routeMete = null;
// 判斷class 是否繼承自 Activity
if (types.isSubtype(tm, type_Activity)) {
Map<String, Integer> paramsType = new HashMap<>();
// 遍歷所有聲明 @Autowired 的屬性
for (Element field : element.getEnclosedElements()) {
// 滿足條件是屬性, 聲明了 @Autowired, 并且沒有實現 iProvider
if (field.getKind().isField() && field.getAnnotation(Autowired.class) != null && !types.isSubtype(field.asType(), iProvider)) {
Autowired paramConfig = field.getAnnotation(Autowired.class);
// 根據 @Autowired 聲明的名字做key, 緩存數據類型的 index 值
paramsType.put(StringUtils.isEmpty(paramConfig.name()) ? field.getSimpleName().toString() : paramConfig.name(), typeUtils.typeExchange(field));
}
}
// 創建 RouteMeta 對象
routeMete = new RouteMeta(route, element, RouteType.ACTIVITY, paramsType);
} else if (types.isSubtype(tm, iProvider)) { // IProvider
routeMete = new RouteMeta(route, element, RouteType.PROVIDER, null);
} else if (types.isSubtype(tm, type_Service)) { // Service
routeMete = new RouteMeta(route, element, RouteType.parse(SERVICE), null);
} else if (types.isSubtype(tm, fragmentTm) || types.isSubtype(tm, fragmentTmV4)) {
routeMete = new RouteMeta(route, element, RouteType.parse(FRAGMENT), null);
}
// 這個方法就是把 route 按照 group 分組保存到 groupMap( Map<String, Set<RouteMeta>> )
categories(routeMete);
}
// 聲明這個方法 public void loadInto(Map<String, RouteMeta> providers)
MethodSpec.Builder loadIntoMethodOfProviderBuilder = MethodSpec.methodBuilder(METHOD_LOAD_INTO)
.addAnnotation(Override.class)
.addModifiers(PUBLIC)
.addParameter(providerParamSpec);
// 開始生成代碼, 遍歷剛才生成的 groupMap
for (Map.Entry<String, Set<RouteMeta>> entry : groupMap.entrySet()) {
String groupName = entry.getKey();
// 聲明方法 public void loadInto(Map<String, RouteMeta> atlas)
MethodSpec.Builder loadIntoMethodOfGroupBuilder = MethodSpec.methodBuilder(METHOD_LOAD_INTO)
.addAnnotation(Override.class)
.addModifiers(PUBLIC)
.addParameter(groupParamSpec);
// 遍歷 group 內保存的 routes
Set<RouteMeta> groupData = entry.getValue();
for (RouteMeta routeMeta : groupData) {
switch (routeMeta.getType()) {
case PROVIDER:
List<? extends TypeMirror> interfaces = ((TypeElement) routeMeta.getRawType()).getInterfaces();
// 生成方法內代碼, 例如下面
// providers.put("com.alibaba.android.arouter.demo.testservice.HelloService", RouteMeta.build(RouteType.PROVIDER, HelloServiceImpl.class, "/service/hello", "service", null, -1, -2147483648));
for (TypeMirror tm : interfaces) {
if (types.isSameType(tm, iProvider)) {
loadIntoMethodOfProviderBuilder.addStatement(
"providers.put($S, $T.build($T." + routeMeta.getType() + ", $T.class, $S, $S, null, " + routeMeta.getPriority() + ", " + routeMeta.getExtra() + "))",
(routeMeta.getRawType()).toString(),
routeMetaCn,
routeTypeCn,
ClassName.get((TypeElement) routeMeta.getRawType()),
routeMeta.getPath(),
routeMeta.getGroup());
} else if (types.isSubtype(tm, iProvider)) {
loadIntoMethodOfProviderBuilder.addStatement(
"providers.put($S, $T.build($T." + routeMeta.getType() + ", $T.class, $S, $S, null, " + routeMeta.getPriority() + ", " + routeMeta.getExtra() + "))",
tm.toString(),
routeMetaCn,
routeTypeCn,
ClassName.get((TypeElement) routeMeta.getRawType()),
routeMeta.getPath(),
routeMeta.getGroup());
}
}
break;
default:
break;
}
// 生成配置的參數類型 map
// 例如 : put("pac", 9); put("obj", 10); put("name", 8); put("boy", 0);
StringBuilder mapBodyBuilder = new StringBuilder();
Map<String, Integer> paramsType = routeMeta.getParamsType();
if (MapUtils.isNotEmpty(paramsType)) {
for (Map.Entry<String, Integer> types : paramsType.entrySet()) {
mapBodyBuilder.append("put(\"").append(types.getKey()).append("\", ").append(types.getValue()).append("); ");
}
}
String mapBody = mapBodyBuilder.toString();
// 生成方法內代碼
// atlas.put("/test/activity2", RouteMeta.build(RouteType.ACTIVITY, Test2Activity.class, "/test/activity2", "test", new java.util.HashMap<String, Integer>(){{put("key1", 8); }}, -1, -2147483648));
loadIntoMethodOfGroupBuilder.addStatement(
"atlas.put($S, $T.build($T." + routeMeta.getType() + ", $T.class, $S, $S, " + (StringUtils.isEmpty(mapBody) ? null : ("new java.util.HashMap<String, Integer>(){{" + mapBodyBuilder.toString() + "}}")) + ", " + routeMeta.getPriority() + ", " + routeMeta.getExtra() + "))",
routeMeta.getPath(),
routeMetaCn,
routeTypeCn,
ClassName.get((TypeElement) routeMeta.getRawType()),
routeMeta.getPath().toLowerCase(),
routeMeta.getGroup().toLowerCase());
}
// 生成 java 文件, 例如 ARouter$$Group$$test.java, ARouter$$Group$$service.java
String groupFileName = NAME_OF_GROUP + groupName;
JavaFile.builder(PACKAGE_OF_GENERATE_FILE,
TypeSpec.classBuilder(groupFileName)
.addJavadoc(WARNING_TIPS)
.addSuperinterface(ClassName.get(type_IRouteGroup))
.addModifiers(PUBLIC)
.addMethod(loadIntoMethodOfGroupBuilder.build())
.build()
).build().writeTo(mFiler);
// 緩存文件名
rootMap.put(groupName, groupFileName);
}
// 生成 ARouter$$Root$$app.java 里的代碼
if (MapUtils.isNotEmpty(rootMap)) {
for (Map.Entry<String, String> entry : rootMap.entrySet()) {
// 生成代碼 : routes.put("service", ARouter$$Group$$service.class);
loadIntoMethodOfRootBuilder.addStatement("routes.put($S, $T.class)", entry.getKey(), ClassName.get(PACKAGE_OF_GENERATE_FILE, entry.getValue()));
}
}
// 生成 providers java 文件. 例如 ARouter$$Providers$$app.java
String providerMapFileName = NAME_OF_PROVIDER + SEPARATOR + moduleName;
JavaFile.builder(PACKAGE_OF_GENERATE_FILE,
TypeSpec.classBuilder(providerMapFileName)
.addJavadoc(WARNING_TIPS)
.addSuperinterface(ClassName.get(type_IProviderGroup))
.addModifiers(PUBLIC)
.addMethod(loadIntoMethodOfProviderBuilder.build())
.build()
).build().writeTo(mFiler);
// 生成 root java 文件. 例如 ARouter$$Root$$app.java
String rootFileName = NAME_OF_ROOT + SEPARATOR + moduleName;
JavaFile.builder(PACKAGE_OF_GENERATE_FILE,
TypeSpec.classBuilder(rootFileName)
.addJavadoc(WARNING_TIPS)
.addSuperinterface(ClassName.get(elements.getTypeElement(ITROUTE_ROOT)))
.addModifiers(PUBLIC)
.addMethod(loadIntoMethodOfRootBuilder.build())
.build()
).build().writeTo(mFiler);
}
總結一下RouteProcessor 做了什么事情
- 根據 @Route 配置 path, group 生成 ARouter$$Root$$"moduleName"
- ARouter$$Root$$xxxx.java 以 group 為 key, 注入了生成的 ARouter$$Group$$xxxx 類
- 根據 @Route 配置 生成 ARouter$$Providers$$"groupName" 和 ARouter$$Group$$"groupName"
- ARouter$$Providers$$xxxx.java 以類為 key, 注入了 IProvider 接口的實現類
- ARouter$$Group$$xxxx.java 以 path 為 key, 注入 RouteMate實例, 描述實現類和 @Autowired 參數描述
RouteProcessor 完成 ARouter 大部分工作, 除了攔截器和自動注入
- InterceptorProcessor init 方法和 RouteProcessor 類似, 直接跳過, 直接看核心方法
// InterceptorProcessor.java
private void parseInterceptors(Set<? extends Element> elements) throws IOException {
for (Element element : elements) {
// 驗證必需實現了 IInterceptor 接口
if (verify(element)) {
Interceptor interceptor = element.getAnnotation(Interceptor.class);
// 根據配置 @Interceptor 的 priority, 返回是否有重復配置的攔截器, 如果有拋出錯誤
Element lastInterceptor = interceptors.get(interceptor.priority());
if (null != lastInterceptor) {
throw new IllegalArgumentException...
}
interceptors.put(interceptor.priority(), element);
}
}
// 聲明類型 Map<Integer, Class<? extends ITollgate>>
ParameterizedTypeName inputMapTypeOfTollgate = ParameterizedTypeName.get(
ClassName.get(Map.class),
ClassName.get(Integer.class),
ParameterizedTypeName.get(
ClassName.get(Class.class),
WildcardTypeName.subtypeOf(ClassName.get(type_ITollgate))
)
);
// 方法參數 interceptors
ParameterSpec tollgateParamSpec = ParameterSpec.builder(inputMapTypeOfTollgate, "interceptors").build();
// 聲明方法 loadInto
MethodSpec.Builder loadIntoMethodOfTollgateBuilder = MethodSpec.methodBuilder(METHOD_LOAD_INTO)
.addAnnotation(Override.class)
.addModifiers(PUBLIC)
.addParameter(tollgateParamSpec);
// 生成方法內代碼, 例如 : interceptors.put(7, Test1Interceptor.class);
for (Map.Entry<Integer, Element> entry : interceptors.entrySet()) {
loadIntoMethodOfTollgateBuilder.addStatement("interceptors.put(" + entry.getKey() + ", $T.class)", ClassName.get((TypeElement) entry.getValue()));
}
// // 生成 Interceptor 的注入代碼, 繼承了 IInterceptorGroup. 例如 ARouter$$Interceptors$$app.java
JavaFile.builder(PACKAGE_OF_GENERATE_FILE,
TypeSpec.classBuilder(NAME_OF_INTERCEPTOR + SEPARATOR + moduleName)
.addModifiers(PUBLIC)
.addJavadoc(WARNING_TIPS)
.addMethod(loadIntoMethodOfTollgateBuilder.build())
.addSuperinterface(ClassName.get(type_ITollgateGroup))
.build()
).build().writeTo(mFiler);
}
InterceptorProcessor 就是生成注入攔截器的代碼, 攔截器有優先級, 并且一個優先級只能一個攔截器
- AutowiredProcessor 負責生成自動注入的代碼, 這點 butterknife 原理差不多
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
categories(roundEnvironment.getElementsAnnotatedWith(Autowired.class));
generateHelper();
}
private void categories(Set<? extends Element> elements) throws IllegalAccessException {
for (Element element : elements) {
TypeElement enclosingElement = (TypeElement) element.getEnclosingElement();
// @Autowired不能修飾 private
if (element.getModifiers().contains(Modifier.PRIVATE)) {
throw new IllegalAccessException("The autowired fields CAN NOT BE 'private'!!! please check field ["
+ element.getSimpleName() + "] in class [" + enclosingElement.getQualifiedName() + "]");
}
// 根據聲明的類分組緩存
if (parentAndChild.containsKey(enclosingElement)) {
parentAndChild.get(enclosingElement).add(element);
} else {
List<Element> childs = new ArrayList<>();
childs.add(element);
parentAndChild.put(enclosingElement, childs);
}
}
}
private void generateHelper() throws IOException, IllegalAccessException {
// 聲明方法參數 Object target
ParameterSpec objectParamSpec = ParameterSpec.builder(TypeName.OBJECT, "target").build();
// 遍歷前面分析后的 parentAndChild
for (Map.Entry<TypeElement, List<Element>> entry : parentAndChild.entrySet()) {
// 聲明方法 public void inject(Object target)
MethodSpec.Builder injectMethodBuilder = MethodSpec.methodBuilder(METHOD_INJECT)
.addAnnotation(Override.class)
.addModifiers(PUBLIC)
.addParameter(objectParamSpec);
TypeElement parent = entry.getKey();
List<Element> childs = entry.getValue();
String qualifiedName = parent.getQualifiedName().toString();
String packageName = qualifiedName.substring(0, qualifiedName.lastIndexOf("."));
// 類名 : com.alibaba.android.arouter.demo.testactivity.Test1Activity
// 生成 : com.alibaba.android.arouter.demo.testactivity.Test1Activity$$ARouter$$Autowired
String fileName = parent.getSimpleName() + NAME_OF_AUTOWIRED;
// 聲明 public class Test1Activity$$ARouter$$Autowired implements ISyringe
TypeSpec.Builder helper = TypeSpec.classBuilder(fileName)
.addJavadoc(WARNING_TIPS)
.addSuperinterface(ClassName.get(type_ISyringe))
.addModifiers(PUBLIC);
// 聲明變量 private SerializationService serializationService;
FieldSpec jsonServiceField = FieldSpec.builder(TypeName.get(type_JsonService.asType()), "serializationService", Modifier.PRIVATE).build();
helper.addField(jsonServiceField);
// 生成代碼 : serializationService = (SerializationService)ARouter.getInstance().navigation(SerializationService.class);
injectMethodBuilder.addStatement("serializationService = $T.getInstance().navigation($T.class);", ARouterClass, ClassName.get(type_JsonService));
// 生成代碼 : Test1Activity substitute = (Test1Activity)target;
injectMethodBuilder.addStatement("$T substitute = ($T)target", ClassName.get(parent), ClassName.get(parent));
// 生成自動注入的代碼
for (Element element : childs) {
Autowired fieldConfig = element.getAnnotation(Autowired.class);
String fieldName = element.getSimpleName().toString();
if (types.isSubtype(element.asType(), iProvider)) {
if ("".equals(fieldConfig.name())) {
// 生成代碼 : substitute.helloService = (HelloService)ARouter.getInstance().navigation(HelloService.class);
injectMethodBuilder.addStatement(
"substitute." + fieldName + " = $T.getInstance().navigation($T.class)",
ARouterClass,
ClassName.get(element.asType())
);
} else {
// 生成代碼 : substitute.helloService = (HelloService)ARouter.getInstance().build("/test/hello").navigation();
injectMethodBuilder.addStatement(
"substitute." + fieldName + " = ($T)$T.getInstance().build($S).navigation();",
ClassName.get(element.asType()),
ARouterClass,
fieldConfig.name()
);
}
} else {
String statment = "substitute." + fieldName + " = substitute.";
boolean isActivity = false;
if (types.isSubtype(parent.asType(), activityTm)) {
isActivity = true;
// activity 直接用getIntent()
statment += "getIntent().";
} else if (types.isSubtype(parent.asType(), fragmentTm) || types.isSubtype(parent.asType(), fragmentTmV4)) {
// fragment 直接用getArguments()
statment += "getArguments().";
} else {
throw new IllegalAccessException("The field [" + fieldName + "] need autowired from intent, its parent must be activity or fragment!");
}
// 生成注入代碼
statment = buildStatement(statment, typeUtils.typeExchange(element), isActivity);
// 判斷serializationService注入
if (statment.startsWith("serializationService.")) {
injectMethodBuilder.beginControlFlow("if (null != serializationService)");
injectMethodBuilder.addStatement(
"substitute." + fieldName + " = " + statment,
(StringUtils.isEmpty(fieldConfig.name()) ? fieldName : fieldConfig.name()),
ClassName.get(element.asType())
);
injectMethodBuilder.nextControlFlow("else");
injectMethodBuilder.addStatement(
"$T.e(\"" + Consts.TAG + "\", \"You want automatic inject the field '" + fieldName + "' in class '$T' , then you should implement 'SerializationService' to support object auto inject!\")", AndroidLog, ClassName.get(parent));
injectMethodBuilder.endControlFlow();
} else {
injectMethodBuilder.addStatement(statment, StringUtils.isEmpty(fieldConfig.name()) ? fieldName : fieldConfig.name());
}
}
}
helper.addMethod(injectMethodBuilder.build());
// 生成 Autowired 的注入代碼, 繼承了 ISyringe. 例如 Test1Activity$$ARouter$$Autowired.java
JavaFile.builder(packageName, helper.build()).build().writeTo(mFiler);
}
}
ARouter 總結
我們已經底 ARouter 大部分代碼都進行了一遍分析, 接下來總結一下 ARouter 工作原理.
編譯期 arouter-compiler 負責生成了注入的的一些代碼:
- ARouter$$Group$$group-name 以 group-name 為文件名注入該 group 下聲明了 @Route 的信息
- ARouter$$Root$$app 按照 group 分組注入了 ARouter$$Group$$group-name
- ARouter$$Providers$$app 注入實現 IProvider 接口的信息
- ARouter$$Interceptors$$app 注入實現 IInterceptor 接口信息
- Test1Activity$$ARouter$$Autowired @Autowired 自動注入的實現
ARouter 初始化的時候會把注入的信息進行緩存
在進行 navigation 的時候, 根據緩存進行懶加載, 然后獲取實際對象或者跳轉 activity.
自動注入就是調用 對應的 Test1Activity$$ARouter$$Autowired 實例, 對聲明 @Autowired 的字段進行復制操作.