本系列文章主要分析 ARouter 框架的架构和原理。
这是阿里 ARouter 开源库的地址,大家可以直接访问https://github.com/alibaba/ARouter
本篇博文主要分析 arouter-compiler 模块;
1 模块结构 下面我们来看看 arouter-compiler 的模块结构:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |____com | |____alibaba | | |____android | | | |____arouter | | | | |____compiler | | | | | |____entity | | | | | | |____RouteDoc.java | | | | | |____processor | | | | | | |____BaseProcessor.java | | | | | | |____InterceptorProcessor.java | | | | | | |____AutowiredProcessor.java | | | | | | |____RouteProcessor.java | | | | | |____utils | | | | | | |____TypeUtils.java | | | | | | |____Consts.java | | | | | | |____Logger.java
可以看到,一共有三个 pacakge:
entity:包含了实体数据类;
processor:包含了所有的注解解释器类;
utils:包含了一些工具类;
我们知道,在 Gradle 对 App 执行编译的时候,arouter-compiler 会对相关的注解进行解析,并动态生成所需的类;
arouter-compiler 模块还依赖了两个三方库:
1 2 implementation 'com.google.auto.service:auto-service:1.0-rc3' implementation 'com.squareup:javapoet:1.8.0'
JavaPoet 是 square 推出的开源 java 代码生成框架,提供 Java Api 生成 .java 源文件;
auto-service 是 google 提供的用于自动注册自定义注解处理器的三方库;
关于这两个库的源码,本系列文章不分析,后面单独分析;
2 源码分析 我们分别分析下三个 package 目录下的 class 的作用!
2.1 entity 该 package 下面只包含一个实体数据类:RouteDoc。
2.1.1 RouteDoc RouteDoc 用于描述路由跳转的信息,用于生成路由表:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 public class RouteDoc { @JSONField (ordinal = 1 ) private String group; @JSONField (ordinal = 2 ) private String path; @JSONField (ordinal = 3 ) private String description; @JSONField (ordinal = 4 ) private String prototype; @JSONField (ordinal = 5 ) private String className; @JSONField (ordinal = 6 ) private String type; @JSONField (ordinal = 7 ) private int mark; @JSONField (ordinal = 8 ) private List<Param> params; ... ... ... public static class Param { @JSONField (ordinal = 1 ) private String key; @JSONField (ordinal = 2 ) private String type; @JSONField (ordinal = 3 ) private String description; @JSONField (ordinal = 4 ) private boolean required; ... ... ... } }
当 processor 对注解进行解析的时候,它会把路由跳转相关的信息记录到 RouteDoc 中!
后面我们分析 processor 的时候就可以看到了!
2.2 processor - 注解解析 该 package 下面包含 ARouter 的核心类:processors,根据前面的注解,一共有三个 processor,我们分别来分析!
重点要关注他们是如何“解析注解,并动态生成代码 的!
2.2.1 BaseProcessor BaseProcessor 是其他三个 processor 的基类,定义了一些共有的属性和操作;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 public abstract class BaseProcessor extends AbstractProcessor { Filer mFiler; Logger logger; Types types; Elements elementUtils; TypeUtils typeUtils; String moduleName = null ; boolean generateDoc; @Override public synchronized void init (ProcessingEnvironment processingEnv) { super .init(processingEnv); mFiler = processingEnv.getFiler(); types = processingEnv.getTypeUtils(); elementUtils = processingEnv.getElementUtils(); typeUtils = new TypeUtils(types, elementUtils); logger = new Logger(processingEnv.getMessager()); Map<String, String> options = processingEnv.getOptions(); if (MapUtils.isNotEmpty(options)) { moduleName = options.get(KEY_MODULE_NAME); generateDoc = VALUE_ENABLE.equals(options.get(KEY_GENERATE_DOC_NAME)); } if (StringUtils.isNotEmpty(moduleName)) { moduleName = moduleName.replaceAll("[^0-9a-zA-Z_]+" , "" ); logger.info("The user has configuration the module name, it was [" + moduleName + "]" ); } else { logger.error(NO_MODULE_NAME_TIPS); throw new RuntimeException("ARouter::Compiler >>> No module name, for more information, look at gradle log." ); } } ... ... ... }
上面省略掉了一些非核心方法,我们不关注它们;
1 2 3 4 5 6 7 8 9 10 11 android { defaultConfig { ... javaCompileOptions { annotationProcessorOptions { arguments = [AROUTER_MODULE_NAME: project.getName(), AROUTER_GENERATE_DOC: "enable" ] } } } }
上面的 KEY_MODULE_NAME,KEY_GENERATE_DOC_NAME,对应的我们在 .gradle 中的配置,这些配置最终都会解析并保存到 ProcessingEnvironment 中;
BaseProcessor 主要作用就是创建 TypeUtils 对象和 Logger 对象,然后获得当前所在 module 的 gradle 配置!
2.2.2 RouteProcessor 核心解释器,用于处理 @Route 注解:
1 2 3 4 5 @AutoService (Processor.class)@SupportedAnnotationTypes ({ANNOTATION_TYPE_ROUTE, ANNOTATION_TYPE_AUTOWIRED})public class RouteProcessor extends BaseProcessor { ... ... ... }
我们从成员变量,初始化,注解处理三个方面来分析:
2.2.2.1 Field 内部变量;
1 2 3 4 5 6 private Map<String, Set<RouteMeta>> groupMap = new HashMap<>();private Map<String, String> rootMap = new TreeMap<>(); private TypeMirror iProvider = null ; private Writer docWriter;
2.2.2.2 Init 初始化 processor:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 @Override public synchronized void init (ProcessingEnvironment processingEnv) { super .init(processingEnv); if (generateDoc) { try { docWriter = mFiler.createResource( StandardLocation.SOURCE_OUTPUT, PACKAGE_OF_GENERATE_DOCS, "arouter-map-of-" + moduleName + ".json" ).openWriter(); } catch (IOException e) { logger.error("Create doc writer failed, because " + e.getMessage()); } } iProvider = elementUtils.getTypeElement(Consts.IPROVIDER).asType(); logger.info(">>> RouteProcessor init. <<<" ); }
2.2.2.3 Process - 处理 Route 注解 核心逻辑:注意,这里的参数 Set<? extends TypeElement> annotations ,表示的是要处理的注解,根据前面的内容:Route 和 AutoWired !
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @Override public boolean process (Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { if (CollectionUtils.isNotEmpty(annotations)) { Set<? extends Element> routeElements = roundEnv.getElementsAnnotatedWith(Route.class); try { logger.info(">>> Found routes, start... <<<" ); this .parseRoutes(routeElements); } catch (Exception e) { logger.error(e); } return true ; } return false ; }
我们看到,这里调用了 parseRoutes 方法:
2.2.2.3.1 parseRoutes 核心的核心:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 private void parseRoutes (Set<? extends Element> routeElements) throws IOException { if (CollectionUtils.isNotEmpty(routeElements)) { logger.info(">>> Found routes, size is " + routeElements.size() + " <<<" ); rootMap.clear(); TypeMirror type_Activity = elementUtils.getTypeElement(ACTIVITY).asType(); TypeMirror type_Service = elementUtils.getTypeElement(SERVICE).asType(); TypeMirror fragmentTm = elementUtils.getTypeElement(FRAGMENT).asType(); TypeMirror fragmentTmV4 = elementUtils.getTypeElement(Consts.FRAGMENT_V4).asType(); TypeElement type_IRouteGroup = elementUtils.getTypeElement(IROUTE_GROUP); TypeElement type_IProviderGroup = elementUtils.getTypeElement(IPROVIDER_GROUP); ClassName routeMetaCn = ClassName.get(RouteMeta.class); ClassName routeTypeCn = ClassName.get(RouteType.class); ParameterizedTypeName inputMapTypeOfRoot = ParameterizedTypeName.get( ClassName.get(Map.class), ClassName.get(String.class), ParameterizedTypeName.get( ClassName.get(Class.class), WildcardTypeName.subtypeOf(ClassName.get(type_IRouteGroup)) ) ); ParameterizedTypeName inputMapTypeOfGroup = ParameterizedTypeName.get( ClassName.get(Map.class), ClassName.get(String.class), ClassName.get(RouteMeta.class) ); ParameterSpec rootParamSpec = ParameterSpec.builder(inputMapTypeOfRoot, "routes" ).build(); ParameterSpec groupParamSpec = ParameterSpec.builder(inputMapTypeOfGroup, "atlas" ).build(); ParameterSpec providerParamSpec = ParameterSpec.builder(inputMapTypeOfGroup, "providers" ).build(); MethodSpec.Builder loadIntoMethodOfRootBuilder = MethodSpec.methodBuilder(METHOD_LOAD_INTO) .addAnnotation(Override.class) .addModifiers(PUBLIC) .addParameter(rootParamSpec); for (Element element : routeElements) { TypeMirror tm = element.asType(); Route route = element.getAnnotation(Route.class); RouteMeta routeMeta; if (types.isSubtype(tm, type_Activity)) { logger.info(">>> Found activity route: " + tm.toString() + " <<<" ); Map<String, Integer> paramsType = new HashMap<>(); Map<String, Autowired> injectConfig = new HashMap<>(); for (Element field : element.getEnclosedElements()) { if (field.getKind().isField() && field.getAnnotation(Autowired.class) != null && !types.isSubtype(field.asType(), iProvider)) { Autowired paramConfig = field.getAnnotation(Autowired.class); String injectName = StringUtils.isEmpty(paramConfig.name()) ? field.getSimpleName().toString() : paramConfig.name(); paramsType.put(injectName, typeUtils.typeExchange(field)); injectConfig.put(injectName, paramConfig); } } routeMeta = new RouteMeta(route, element, RouteType.ACTIVITY, paramsType); routeMeta.setInjectConfig(injectConfig); } else if (types.isSubtype(tm, iProvider)) { logger.info(">>> Found provider route: " + tm.toString() + " <<<" ); routeMeta = new RouteMeta(route, element, RouteType.PROVIDER, null ); } else if (types.isSubtype(tm, type_Service)) { logger.info(">>> Found service route: " + tm.toString() + " <<<" ); routeMeta = new RouteMeta(route, element, RouteType.parse(SERVICE), null ); } else if (types.isSubtype(tm, fragmentTm) || types.isSubtype(tm, fragmentTmV4)) logger.info(">>> Found fragment route: " + tm.toString() + " <<<" ); routeMeta = new RouteMeta(route, element, RouteType.parse(FRAGMENT), null ); } else { throw new RuntimeException("ARouter::Compiler >>> Found unsupported class type, type = [" + types.toString() + "]." ); } categories(routeMeta); } MethodSpec.Builder loadIntoMethodOfProviderBuilder = MethodSpec.methodBuilder(METHOD_LOAD_INTO) .addAnnotation(Override.class) .addModifiers(PUBLIC) .addParameter(providerParamSpec); Map<String, List<RouteDoc>> docSource = new HashMap<>(); for (Map.Entry<String, Set<RouteMeta>> entry : groupMap.entrySet()) { String groupName = entry.getKey(); MethodSpec.Builder loadIntoMethodOfGroupBuilder = MethodSpec.methodBuilder(METHOD_LOAD_INTO) .addAnnotation(Override.class) .addModifiers(PUBLIC) .addParameter(groupParamSpec); List<RouteDoc> routeDocList = new ArrayList<>(); Set<RouteMeta> groupData = entry.getValue(); for (RouteMeta routeMeta : groupData) { RouteDoc routeDoc = extractDocInfo(routeMeta); ClassName className = ClassName.get((TypeElement) routeMeta.getRawType()); switch (routeMeta.getType()) { case PROVIDER: List<? extends TypeMirror> interfaces = ((TypeElement) routeMeta.getRawType()).getInterfaces(); for (TypeMirror tm : interfaces) { routeDoc.addPrototype(tm.toString()); 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, 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, routeMeta.getPath(), routeMeta.getGroup()); } } break ; default : break ; } StringBuilder mapBodyBuilder = new StringBuilder(); Map<String, Integer> paramsType = routeMeta.getParamsType(); Map<String, Autowired> injectConfigs = routeMeta.getInjectConfig(); if (MapUtils.isNotEmpty(paramsType)) { List<RouteDoc.Param> paramList = new ArrayList<>(); for (Map.Entry<String, Integer> types : paramsType.entrySet()) { mapBodyBuilder.append("put(\"" ).append(types.getKey()).append("\", " ).append(types.getValue()).append("); " ); RouteDoc.Param param = new RouteDoc.Param(); Autowired injectConfig = injectConfigs.get(types.getKey()); param.setKey(types.getKey()); param.setType(TypeKind.values()[types.getValue()].name().toLowerCase()); param.setDescription(injectConfig.desc()); param.setRequired(injectConfig.required()); paramList.add(param); } routeDoc.setParams(paramList); } String mapBody = mapBodyBuilder.toString(); 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, routeMeta.getPath().toLowerCase(), routeMeta.getGroup().toLowerCase()); routeDoc.setClassName(className.toString()); routeDocList.add(routeDoc); } 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); logger.info(">>> Generated group: " + groupName + "<<<" ); rootMap.put(groupName, groupFileName); docSource.put(groupName, routeDocList); } if (MapUtils.isNotEmpty(rootMap)) { for (Map.Entry<String, String> entry : rootMap.entrySet()) { loadIntoMethodOfRootBuilder.addStatement("routes.put($S, $T.class)" , entry.getKey(), ClassName.get(PACKAGE_OF_GENERATE_FILE, entry.getValue())); } } if (generateDoc) { docWriter.append(JSON.toJSONString(docSource, SerializerFeature.PrettyFormat)); docWriter.flush(); docWriter.close(); } 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); logger.info(">>> Generated provider map, name is " + providerMapFileName + " <<<" ); String rootFileName = NAME_OF_ROOT + SEPARATOR + moduleName; JavaFile.builder(PACKAGE_OF_GENERATE_FILE, TypeSpec.classBuilder(rootFileName) .addJavadoc(WARNING_TIPS) .addSuperinterface(ClassName.get(elementUtils.getTypeElement(ITROUTE_ROOT))) .addModifiers(PUBLIC) .addMethod(loadIntoMethodOfRootBuilder.build()) .build() ).build().writeTo(mFiler); logger.info(">>> Generated root, name is " + rootFileName + " <<<" ); } }
整个流程还是很简单清晰的,主要是代码生成过程用很多的占位符,为我们看源码产生了很多的阻碍;
RouteProcessor 不仅会解析 @Route,还会解析 @AutoWired;
最终会生成三个 java 文件,具体的模版信息:
2.2.2.3.1.1 categories 对跳转信息进行分类;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 private void categories (RouteMeta routeMete) { if (routeVerify(routeMete)) { logger.info(">>> Start categories, group = " + routeMete.getGroup() + ", path = " + routeMete.getPath() + " <<<" ); Set<RouteMeta> routeMetas = groupMap.get(routeMete.getGroup()); if (CollectionUtils.isEmpty(routeMetas)) { Set<RouteMeta> routeMetaSet = new TreeSet<>(new Comparator<RouteMeta>() { @Override public int compare (RouteMeta r1, RouteMeta r2) { try { return r1.getPath().compareTo(r2.getPath()); } catch (NullPointerException npe) { logger.error(npe.getMessage()); return 0 ; } } }); routeMetaSet.add(routeMete); groupMap.put(routeMete.getGroup(), routeMetaSet); } else { routeMetas.add(routeMete); } } else { logger.warning(">>> Route meta verify error, group is " + routeMete.getGroup() + " <<<" ); } }
end~
2.2.2.3.1.2 routeVerify 校验路由跳转信息;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 private boolean routeVerify (RouteMeta meta) { String path = meta.getPath(); if (StringUtils.isEmpty(path) || !path.startsWith("/" )) { return false ; } if (StringUtils.isEmpty(meta.getGroup())) { try { String defaultGroup = path.substring(1 , path.indexOf("/" , 1 )); if (StringUtils.isEmpty(defaultGroup)) { return false ; } meta.setGroup(defaultGroup); return true ; } catch (Exception e) { logger.error("Failed to extract default group! " + e.getMessage()); return false ; } } return true ; }
不多说了~
创建路由信息对象:
1 2 3 4 5 6 7 8 9 10 11 private RouteDoc extractDocInfo (RouteMeta routeMeta) { RouteDoc routeDoc = new RouteDoc(); routeDoc.setGroup(routeMeta.getGroup()); routeDoc.setPath(routeMeta.getPath()); routeDoc.setDescription(routeMeta.getName()); routeDoc.setType(routeMeta.getType().name().toLowerCase()); routeDoc.setMark(routeMeta.getExtra()); return routeDoc; }
2.2.5.4 动态生成类 2.2.5.4.1 模版信息 我们来看看生成了哪几种模板类:
ARouter$$Providers$$${moduleName}.java
这个模版类继承了 IProviderGroup,其实都可以猜到,用于添加属于同一组的 iprovider:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package com.alibaba.android.arouter.routes;import com.alibaba.android.arouter.facade.enums.RouteType;import com.alibaba.android.arouter.facade.model.RouteMeta;import com.alibaba.android.arouter.facade.template.IProviderGroup;import java.lang.Override;import java.lang.String;import java.util.Map;... ... ... public class ARouter $$Providers $$$ {moduleName} implements IProviderGroup { @Override public void loadInto (Map<String, RouteMeta> providers) { providers.put("目标类的全限定名" , RouteMeta.build(RouteType.PROVIDER, 目标类的类名.class, ${routeMeta.getPath()}, ${routeMeta.getGroup()}, null , ${routeMeta.getPriority()}, ${routeMeta.getExtra()})); providers.put("父类的全限定名" , RouteMeta.build(RouteType.PROVIDER, 目标类的类名.class, ${routeMeta.getPath()}, ${routeMeta.getGroup()}, null , ${routeMeta.getPriority()}, ${routeMeta.getExtra()})); } }
不多说了~
ARouter$$Group$$${groupName}.java
这个模版类继承了 IRouteGroup,其实都可以猜到,用于添加属于同一组的所有被 @Route 注解的元素:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package com.alibaba.android.arouter.routes;import com.alibaba.android.arouter.facade.enums.RouteType;import com.alibaba.android.arouter.facade.model.RouteMeta;import com.alibaba.android.arouter.facade.template.IRouteGroup;import java.lang.Override;import java.lang.String;import java.util.Map;... ... ... public class ARouter $$Group $$$ {groupName} implements IRouteGroup { @Override public void loadInto (Map<String, RouteMeta> atlas) { atlas.put(${path}, RouteMeta.build(RouteType.XXXX, ${className}.class, ${path}, ${group}, new java.util.HashMap<String, Integer>(){{put(${fieldName}/${AutoWired.Name}, ${TypeKind});}}, ${priority}, ${extra})); atlas.put(${path}, RouteMeta.build(RouteType.XXXX, ${className}.class, ${path}, ${group}, null , ${priority}, ${extra})); } }
不多说了~
ARouter$$Root$$${moduleName}.java
这个模版类继承了 IRouteRoot,最为 root,用于添加和管理 group 和对应的 ARouter$$Group$$${moduleName}.java
的映射关系;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package com.alibaba.android.arouter.routes;import com.alibaba.android.arouter.facade.template.IRouteGroup;import com.alibaba.android.arouter.facade.template.IRouteRoot;import java.lang.Class;import java.lang.Override;import java.lang.String;import java.util.Map;public class ARouter $$Root $$$ {moduleName} implements IRouteRoot { @Override public void loadInto (Map<String, Class<? extends IRouteGroup>> routes) { routes.put(${groupName}, ARouter$$Group$$${groupName}.class); } }
我们可以通过 ARouter$$Root$$${groupName}.java
知道该 module 一共包含多少个 group。每个组中的的元素,可以通过 ARouter$$Group$$${moduleName}.java
这个文档添加;
2.2.5.4.2 举个栗子 我写了个 Demo 可以让大家更直观的看到模版对应的实际代码:
2.2.5.4.2.1 实例代码 下面是一个简单的 Demo:
MyActivity 的组是:coolqiActivity
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 package com.lishuaiqi.test;import android.app.Activity;import android.os.Bundle;import android.support.annotation.Nullable;import com.alibaba.android.arouter.facade.annotation.Autowired;import com.alibaba.android.arouter.facade.annotation.Route;import com.alibaba.android.arouter.launcher.ARouter;@Route (path = "/coolqiActivity/MyActivity" )public class MyActivity extends Activity { @Autowired (name = "isOneAuto" ) public boolean isOne; @Autowired (name = "isTwoAuto" ) public int isTwo; @Override protected void onCreate (@Nullable Bundle savedInstanceState) { super .onCreate(savedInstanceState); ARouter.getInstance().inject(this ); } }
MyIProvider 的组是:coolqiProvider
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package com.lishuaiqi.test;import android.content.Context;import com.alibaba.android.arouter.facade.annotation.Route;import com.alibaba.android.arouter.facade.template.IProvider;@Route (path = "/coolqiProvider/MyIProvider" )public class MyProvider implements IProvider { @Override public void init (Context context) { } }
MySerializationService.java
MySerializationService 的组是:coolqiService
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 @Route (path = "/coolqiService/MySerializationService" )public class MySerializationService implements SerializationService { @Override public <T> T json2Object (String input, Class<T> clazz) { return null ; } @Override public String object2Json (Object instance) { return null ; } @Override public <T> T parseObject (String input, Type clazz) { return null ; } @Override public void init (Context context) { } }
我是新建了一个 Module,名字叫:Coolqi
2.2.5.4.2.2 动态代码 动态的代码如下所示:
ARouter$$Group$$coolqiActivity.java
, ARouter$$Group$$coolqiProvider.java
, ARouter$$Group$$coolqiService.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 package com.alibaba.android.arouter.routes;import com.alibaba.android.arouter.facade.enums.RouteType;import com.alibaba.android.arouter.facade.model.RouteMeta;import com.alibaba.android.arouter.facade.template.IRouteGroup;import com.lishuaiqi.test.MyActivity;import com.lishuaiqi.test.MyPathReplaceService;import com.lishuaiqi.test.MyProvider;import com.lishuaiqi.MainActivity;import java.lang.Override;import java.lang.String;import java.util.Map;public class ARouter $$Group $$coolqiActivity implements IRouteGroup { @Override public void loadInto (Map<String, RouteMeta> atlas) { atlas.put("/coolqiActivity/MyActivity" , RouteMeta.build(RouteType.ACTIVITY, MyActivity.class, "/coolqiactivity/myactivity" , "coolqiactivity" , null , -1 , -2147483648 )); } } public class ARouter $$Group $$coolqiProvider implements IRouteGroup { @Override public void loadInto (Map<String, RouteMeta> atlas) { atlas.put("/coolqiProvider/MyIProvider" , RouteMeta.build(RouteType.PROVIDER, MyIProvider.class, "/coolqiprovider/myiprovider" , "coolqiprovider" , null , -1 , -2147483648 )); } } public class ARouter $$Group $$coolqiService implements IRouteGroup { @Override public void loadInto (Map<String, RouteMeta> atlas) { atlas.put("/coolqiService/MySerializationService" , RouteMeta.build(RouteType.PROVIDER, MySerializationService.class, "/coolqiservice/myserializationservice" , "coolqiservice" , null , -1 , -2147483648 )); } }
其他的就不说了,反正就是看代码!
ARouter$$Providers$$app.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package com.alibaba.android.arouter.routes;import com.alibaba.android.arouter.facade.enums.RouteType;import com.alibaba.android.arouter.facade.model.RouteMeta;import com.alibaba.android.arouter.facade.template.IProviderGroup;import com.pa.sales2.test.MyIProvider;import com.pa.sales2.test.MySerializationService;import java.lang.Override;import java.lang.String;import java.util.Map;public class ARouter $$Providers $$Coolqi implements IProviderGroup { @Override public void loadInto (Map<String, RouteMeta> providers) { providers.put("com.alibaba.android.arouter.facade.service.SerializationService" , RouteMeta.build(RouteType.PROVIDER, MySerializationService.class, "/coolqiService/MySerializationService" , "coolqiService" , null , -1 , -2147483648 )); providers.put("com.pa.sales2.test.MyIProvider" , RouteMeta.build(RouteType.PROVIDER, MyIProvider.class, "/coolqiProvider/MyIProvider" , "coolqiProvider" , null , -1 , -2147483648 )); } }
其他的就不说了,反正就是看代码!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 package com.alibaba.android.arouter.routes;import com.alibaba.android.arouter.facade.template.IRouteGroup;import com.alibaba.android.arouter.facade.template.IRouteRoot;import java.lang.Class;import java.lang.Override;import java.lang.String;import java.util.Map;public class ARouter $$Root $$Coolqi implements IRouteRoot { @Override public void loadInto (Map<String, Class<? extends IRouteGroup>> routes) { routes.put("coolqiActivity" , ARouter$$Group$$coolqiActivity.class); routes.put("coolqiProvider" , ARouter$$Group$$coolqiProvider.class); routes.put("coolqiService" , ARouter$$Group$$coolqiService.class); } }
其他的就不说了,反正就是看代码!
2.2.3 AutowiredProcessor 核心解释器,用于处理 @Autowired 注解:
1 2 3 4 5 @AutoService (Processor.class)@SupportedAnnotationTypes ({ANNOTATION_TYPE_AUTOWIRED})public class AutowiredProcessor extends BaseProcessor { ... ... ... }
我们从成员变量,初始化,注解处理三个方面来分析:
2.2.3.1 Field 1 2 3 4 private Map<TypeElement, List<Element>> parentAndChild = new HashMap<>(); private static final ClassName ARouterClass = ClassName.get("com.alibaba.android.arouter.launcher" , "ARouter" );private static final ClassName AndroidLog = ClassName.get("android.util" , "Log" );
2.2.3.2 Init init 方法很简单,没有太多代码:
1 2 3 4 5 @Override public synchronized void init (ProcessingEnvironment processingEnvironment) { super .init(processingEnvironment); logger.info(">>> AutowiredProcessor init. <<<" ); }
2.2.3.3 Process - 处理 Autowired 注解 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @Override public boolean process (Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) { if (CollectionUtils.isNotEmpty(set)) { try { logger.info(">>> Found autowired field, start... <<<" ); categories(roundEnvironment.getElementsAnnotatedWith(Autowired.class)); generateHelper(); } catch (Exception e) { logger.error(e); } return true ; } return false ; }
2.2.3.3.1 categories 对变量进行归类,并找到其所属的类;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 private void categories (Set<? extends Element> elements) throws IllegalAccessException { if (CollectionUtils.isNotEmpty(elements)) { for (Element element : elements) { TypeElement enclosingElement = (TypeElement) element.getEnclosingElement(); if (element.getModifiers().contains(Modifier.PRIVATE)) { throw new IllegalAccessException("The inject 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); } } logger.info("categories finished." ); } }
可以看到,private 的元素不能用 Autowired 修饰;
2.2.3.3.2 generateHelper 动态生成 java 类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 private void generateHelper () throws IOException, IllegalAccessException { TypeElement type_ISyringe = elementUtils.getTypeElement(ISYRINGE); TypeElement type_JsonService = elementUtils.getTypeElement(JSON_SERVICE); TypeMirror iProvider = elementUtils.getTypeElement(Consts.IPROVIDER).asType(); TypeMirror activityTm = elementUtils.getTypeElement(Consts.ACTIVITY).asType(); TypeMirror fragmentTm = elementUtils.getTypeElement(Consts.FRAGMENT).asType(); TypeMirror fragmentTmV4 = elementUtils.getTypeElement(Consts.FRAGMENT_V4).asType(); ParameterSpec objectParamSpec = ParameterSpec.builder(TypeName.OBJECT, "target" ).build(); if (MapUtils.isNotEmpty(parentAndChild)) { for (Map.Entry<TypeElement, List<Element>> entry : parentAndChild.entrySet()) { 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("." )); String fileName = parent.getSimpleName() + NAME_OF_AUTOWIRED; logger.info(">>> Start process " + childs.size() + " field in " + parent.getSimpleName() + " ... <<<" ); TypeSpec.Builder helper = TypeSpec.classBuilder(fileName) .addJavadoc(WARNING_TIPS) .addSuperinterface(ClassName.get(type_ISyringe)) .addModifiers(PUBLIC); FieldSpec jsonServiceField = FieldSpec.builder(TypeName.get(type_JsonService.asType()), "serializationService" , Modifier.PRIVATE).build(); helper.addField(jsonServiceField); injectMethodBuilder.addStatement("serializationService = $T.getInstance().navigation($T.class)" , ARouterClass, ClassName.get(type_JsonService)); 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())) { injectMethodBuilder.addStatement( "substitute." + fieldName + " = $T.getInstance().navigation($T.class)" , ARouterClass, ClassName.get(element.asType()) ); } else { injectMethodBuilder.addStatement( "substitute." + fieldName + " = ($T)$T.getInstance().build($S).navigation()" , ClassName.get(element.asType()), ARouterClass, fieldConfig.name() ); } if (fieldConfig.required()) { injectMethodBuilder.beginControlFlow("if (substitute." + fieldName + " == null)" ); injectMethodBuilder.addStatement( "throw new RuntimeException(\"The field '" + fieldName + "' is null, in class '\" + $T.class.getName() + \"!\")" , ClassName.get(parent)); injectMethodBuilder.endControlFlow(); } } else { String originalValue = "substitute." + fieldName; String statement = "substitute." + fieldName + " = " + buildCastCode(element) + "substitute." ; boolean isActivity = false ; if (types.isSubtype(parent.asType(), activityTm)) { isActivity = true ; statement += "getIntent()." ; } else if (types.isSubtype(parent.asType(), fragmentTm) || types.isSubtype(parent.asType(), fragmentTmV4)) { statement += "getArguments()." ; } else { throw new IllegalAccessException("The field [" + fieldName + "] need autowired from intent, " + "its parent must be activity or fragment!" ); } statement = buildStatement(originalValue, statement, typeUtils.typeExchange(element), isActivity); if (statement.startsWith("serializationService." )) { injectMethodBuilder.beginControlFlow("if (null != serializationService)" ); injectMethodBuilder.addStatement( "substitute." + fieldName + " = " + statement, (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(statement, StringUtils.isEmpty(fieldConfig.name()) ? fieldName : fieldConfig.name()); } if (fieldConfig.required() && !element.asType().getKind().isPrimitive()) { injectMethodBuilder.beginControlFlow("if (null == substitute." + fieldName + ")" ); injectMethodBuilder.addStatement( "$T.e(\"" + Consts.TAG + "\", \"The field '" + fieldName + "' is null, in class '\" + $T.class.getName() + \"!\")" , AndroidLog, ClassName.get(parent)); injectMethodBuilder.endControlFlow(); } } } helper.addMethod(injectMethodBuilder.build()); JavaFile.builder(packageName, helper.build()).build().writeTo(mFiler); logger.info(">>> " + parent.getSimpleName() + " has been processed, " + fileName + " has been generated. <<<" ); } logger.info(">>> Autowired processor stop. <<<" ); } }
整个流程我们分析完成了,我们先不关注动态生成的类的作用,在后面分析 arouter-api 模块的时候,就会知道这些类的作用是什么了。
2.2.3.3.2.1 buildCastCode 判断 element 的类型是否是 SERIALIZABLE 的,这里利用到了前面的枚举类 TypeKind 和工具类 typeUtils:
1 2 3 4 5 6 7 8 private String buildCastCode (Element element) { if (typeUtils.typeExchange(element) == TypeKind.SERIALIZABLE.ordinal()) { return CodeBlock.builder().add("($T) " , ClassName.get(element.asType())).build().toString(); } return "" ; }
这个主要是针对于实现了 serializable 接口的变量,比如一些集合等等;
2.2.3.3.2.2 buildStatement 处理 getIntent()/getArguments() 的数据:
参数 originalValue 表示变量: “substitute.fieldName“,用于返回默认值;
参数 type 是成员属性对应的枚举序号:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 private String buildStatement (String originalValue, String statement, int type, boolean isActivity) { switch (TypeKind.values()[type]) { case BOOLEAN: statement += (isActivity ? ("getBooleanExtra($S, " + originalValue + ")" ) : ("getBoolean($S)" )); break ; case BYTE: statement += (isActivity ? ("getByteExtra($S, " + originalValue + ")" ) : ("getByte($S)" )); break ; case SHORT: statement += (isActivity ? ("getShortExtra($S, " + originalValue + ")" ) : ("getShort($S)" )); break ; case INT: statement += (isActivity ? ("getIntExtra($S, " + originalValue + ")" ) : ("getInt($S)" )); break ; case LONG: statement += (isActivity ? ("getLongExtra($S, " + originalValue + ")" ) : ("getLong($S)" )); break ; case CHAR: statement += (isActivity ? ("getCharExtra($S, " + originalValue + ")" ) : ("getChar($S)" )); break ; case FLOAT: statement += (isActivity ? ("getFloatExtra($S, " + originalValue + ")" ) : ("getFloat($S)" )); break ; case DOUBLE: statement += (isActivity ? ("getDoubleExtra($S, " + originalValue + ")" ) : ("getDouble($S)" )); break ; case STRING: statement += (isActivity ? ("getExtras() == null ? " + originalValue + " : substitute.getIntent().getExtras().getString($S, " + originalValue + ")" ) : ("getString($S)" )); break ; case SERIALIZABLE: statement += (isActivity ? ("getSerializableExtra($S)" ) : ("getSerializable($S)" )); break ; case PARCELABLE: statement += (isActivity ? ("getParcelableExtra($S)" ) : ("getParcelable($S)" )); break ; case OBJECT: statement = "serializationService.parseObject(substitute." + (isActivity ? "getIntent()." : "getArguments()." ) + (isActivity ? "getStringExtra($S)" : "getString($S)" ) + ", new " + TYPE_WRAPPER + "<$T>(){}.getType())" ; break ; } return statement; }
可以看到,buildStatement 会处理 getIntent()/getArguments() 的数据,在 statement 基础上拼接/修改:
变量类型
动态生成的代码块
boolean
substitute.变量 = substitute.getIntent().getBooleanExtra($S, 变量)
byte
substitute.变量 = substitute.getIntent().getByteExtra($S, 变量)
short
substitute.变量 = substitute.getIntent().getShortExtra($S, 变量)
int
substitute.变量 = substitute.getIntent().getIntExtra($S, 变量)
long
substitute.变量 = substitute.getIntent().getLongExtra($S, 变量)
char
substitute.变量 = substitute.getIntent().getCharExtra($S, 变量)
float
substitute.变量 = substitute.getIntent().getFloatExtra($S, 变量)
double
substitute.变量 = substitute.getIntent().getDoubleExtra($S, 变量)
string
substitute.变量 = substitute.getIntent().getExtras() == null ? 变量 : substitute.getIntent().getExtras().getString($S, 变量)
serializable
substitute.变量 = (变量类型的全限定名) substitute.getIntent().getSerializableExtra($S)
parcelable
substitute.变量 = substitute.getIntent().getParcelableExtra($S)
object
serializationService.parseObject(substitute.getIntent().getStringExtra($S), new com.alibaba.android.arouter.facade.model.TypeWrapper<$T>(){}.getType())
这里的 $S, $T
,依然是作为占位符,并没有被替换成实体的类型;
变量类型
动态生成的代码块
boolean
substitute.变量 = substitute.getArguments().getBoolean($S)
byte
substitute.变量 = substitute.getArguments().getByte($S)
short
substitute.变量 = substitute.getArguments().getShort($S)
int
substitute.变量 = substitute.getArguments().getInt($S)
long
substitute.变量 = substitute.getArguments().getLong($S)
char
substitute.变量 = substitute.getArguments().getChar($S)
float
substitute.变量 = substitute.getArguments().getFloat($S)
double
substitute.变量 = substitute.getArguments().getDouble($S)
string
substitute.变量 = substitute.getArguments().getString($S)
serializable
substitute.变量 = (变量类型的全限定名) substitute.getArguments().getSerializable($S)
parcelable
substitute.变量 = substitute.getArguments().getParcelable($S)
object
serializationService.parseObject(substitute.getArguments().getString($S), new com.alibaba.android.arouter.facade.model.TypeWrapper<$T>(){}.getType())
这里的 $S, $T
,依然是作为占位符,并没有被替换成实体的类型;
返回的 statement 会继续被处理!
2.2.3.4 动态生成类 2.2.3.4.1 模版信息 我们来看一下,解析 AutoWired 后动态生成的 java 类的模版:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 package 所属类所在的包;import com.alibaba.android.arouter.facade.template.ISyringe;import com.alibaba.android.arouter.facade.service.SerializationService;import com.alibaba.android.arouter.launcher.ARouter;import ... ... ...class 所属类的类名$$ARouter $$Root $$Autowired implements ISyringe { private SerializationService serializationService; @Override public void inject (Object target) { serializationService = ARouter.getInstance().navigation(SerializationService.class); 所属类的全限定名 substitute = (所属类的全限定名) target; substitute.变量 = ARouter.getInstance().navigation(变量类型的全限定名.class); substitute.变量 = (变量类型) ARouter.getInstance().build(Autowired.name).navigation(); if (substitute.变量 == null ) { throw new RuntimeException(...); } substitute.变量 = substitute.getIntent().getBooleanExtra(变量名/Autowired.name, substitute.变量); substitute.变量 = substitute.getIntent().getByteExtra(变量名/Autowired.name, substitute.变量); substitute.变量 = substitute.getIntent().getShortExtra(变量名/Autowired.name, substitute.变量); substitute.变量 = substitute.getIntent().getIntExtra(变量名/Autowired.name, substitute.变量); substitute.变量 = substitute.getIntent().getCharExtra(变量名/Autowired.name, substitute.变量); substitute.变量 = substitute.getIntent().getFloatExtra(变量名/Autowired.name, substitute.变量); substitute.变量 = substitute.getIntent().getDoubleExtra(变量名/Autowired.name, substitute.变量); substitute.变量 = substitute.getIntent().getExtras() == null ? substitute.变量 : substitute.getIntent().getExtras().getString(变量名/Autowired.name, substitute.变量); substitute.变量 = (变量类型) substitute.getIntent().getSerializableExtra(变量名/Autowired.name); substitute.变量 = substitute.getIntent().getParcelableExtra(变量名/Autowired.name); substitute.变量 = serializationService.parseObject(substitute.getIntent().getStringExtra(变量名/Autowired.name), new com.alibaba.android.arouter.facade.model.TypeWrapper<变量类型>(){}.getType()); substitute.变量 = substitute.getArguments().getBoolean(变量名/Autowired.name); substitute.变量 = substitute.getArguments().getByte(变量名/Autowired.name); substitute.变量 = substitute.getArguments().getShort(变量名/Autowired.name); substitute.变量 = substitute.getArguments().getInt(变量名/Autowired.name); substitute.变量 = substitute.getArguments().getLong(变量名/Autowired.name); substitute.变量 = substitute.getArguments().getChar(变量名/Autowired.name); substitute.变量 = substitute.getArguments().getFloat(变量名/Autowired.name); substitute.变量 = substitute.getArguments().getDouble(变量名/Autowired.name); substitute.变量 = substitute.getArguments().getString(变量名/Autowired.name); substitute.变量 = (变量类型) substitute.getArguments().getSerializable(变量名/Autowired.name); substitute.变量 = substitute.getArguments().getParcelable(变量名/Autowired.name); serializationService.parseObject(substitute.getArguments().getString(变量名/Autowired.name), new com.alibaba.android.arouter.facade.model.TypeWrapper<变量类型>(){}.getType()); } }
其实大家可以看的出来,inject 方法就是用来自动给成员变量赋值的;
2.2.3.4.2 举个栗子 2.2.3.4.2.1 实例代码 以 activity 为例子;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 package com.lishuaiqi.test;import android.app.Activity;import android.os.Bundle;import android.support.annotation.Nullable;import com.alibaba.android.arouter.facade.annotation.Autowired;import com.alibaba.android.arouter.facade.annotation.Route;import com.alibaba.android.arouter.launcher.ARouter;@Route (path = "/app/MyActivity" )public class MyActivity extends Activity { @Autowired (name = "isOneAuto" ) public boolean isOne; @Autowired (name = "isTwoAuto" ) public int isTwo; @Override protected void onCreate (@Nullable Bundle savedInstanceState) { super .onCreate(savedInstanceState); ARouter.getInstance().inject(this ); } }
2.2.3.4.2.2 动态代码 如下是动态代码了,不多说了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 package com.lishuaiqi.test;import com.alibaba.android.arouter.facade.service.SerializationService;import com.alibaba.android.arouter.facade.template.ISyringe;import com.alibaba.android.arouter.launcher.ARouter;import java.lang.Object;import java.lang.Override;public class MyActivity $$ARouter $$Autowired implements ISyringe { private SerializationService serializationService; @Override public void inject (Object target) { serializationService = ARouter.getInstance().navigation(SerializationService.class); MyActivity substitute = (MyActivity)target; substitute.isOne = substitute.getIntent().getBooleanExtra("isOneAuto" , substitute.isOne); substitute.isTwo = substitute.getIntent().getIntExtra("isTwoAuto" , substitute.isTwo); } }
2.2.4 InterceptorProcessor 核心解释器,用于处理 @Interceptor 注解:
1 2 3 4 5 @AutoService (Processor.class)@SupportedAnnotationTypes (ANNOTATION_TYPE_INTECEPTOR)public class InterceptorProcessor extends BaseProcessor { ... ... ... }
我们从成员变量,初始化,注解处理三个方面来分析:
2.2.4.1 Field 成员变量有两个:
1 2 3 4 private Map<Integer, Element> interceptors = new TreeMap<>();private TypeMirror iInterceptor = null ;
2.2.4.2 Init 初始化操作:
1 2 3 4 5 6 7 8 @Override public synchronized void init (ProcessingEnvironment processingEnv) { super .init(processingEnv); iInterceptor = elementUtils.getTypeElement(Consts.IINTERCEPTOR).asType(); logger.info(">>> InterceptorProcessor init. <<<" ); }
这里的 Consts.IINTERCEPTOR 是 IInterceptor 接口的全限定名:
com.alibaba.android.arouter.facade.template.IInterceptor
2.2.4.3 Process - 处理 Interceptor 注解 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @Override public boolean process (Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { if (CollectionUtils.isNotEmpty(annotations)) { Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(Interceptor.class); try { parseInterceptors(elements); } catch (Exception e) { logger.error(e); } return true ; } return false ; }
核心逻辑在 parseInterceptors 中;
2.2.4.3.1 parseInterceptors 我们来看下如何解析元素:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 private void parseInterceptors (Set<? extends Element> elements) throws IOException { if (CollectionUtils.isNotEmpty(elements)) { logger.info(">>> Found interceptors, size is " + elements.size() + " <<<" ); for (Element element : elements) { if (verify(element)) { logger.info("A interceptor verify over, its " + element.asType()); Interceptor interceptor = element.getAnnotation(Interceptor.class); Element lastInterceptor = interceptors.get(interceptor.priority()); if (null != lastInterceptor) { throw new IllegalArgumentException( String.format(Locale.getDefault(), "More than one interceptors use same" + "priority [%d], They are [%s] and [%s]." , interceptor.priority(), lastInterceptor.getSimpleName(), element.getSimpleName()) ); } interceptors.put(interceptor.priority(), element); } else { logger.error("A interceptor verify failed, its " + element.asType()); } } TypeElement type_ITollgate = elementUtils.getTypeElement(IINTERCEPTOR); TypeElement type_ITollgateGroup = elementUtils.getTypeElement(IINTERCEPTOR_GROUP); ParameterizedTypeName inputMapTypeOfTollgate = ParameterizedTypeName.get( ClassName.get(Map.class), ClassName.get(Integer.class), ParameterizedTypeName.get( ClassName.get(Class.class), WildcardTypeName.subtypeOf(ClassName.get(type_ITollgate)) ) ); ParameterSpec tollgateParamSpec = ParameterSpec.builder(inputMapTypeOfTollgate, "interceptors" ).build(); MethodSpec.Builder loadIntoMethodOfTollgateBuilder = MethodSpec.methodBuilder(METHOD_LOAD_INTO) .addAnnotation(Override.class) .addModifiers(PUBLIC) .addParameter(tollgateParamSpec); if (null != interceptors && interceptors.size() > 0 ) { for (Map.Entry<Integer, Element> entry : interceptors.entrySet()) { loadIntoMethodOfTollgateBuilder.addStatement("interceptors.put(" + entry.getKey() + ", $T.class)" , ClassName.get((TypeElement) entry.getValue())); } } 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); logger.info(">>> Interceptor group write over. <<<" ); } }
可以看到其是使用 javapoet 三方库来懂爱生成 .java 文件;
2.2.4.3.1.1 verify 校验元素和注解的正确性:
1 2 3 4 5 6 7 private boolean verify (Element element) { Interceptor interceptor = element.getAnnotation(Interceptor.class); return null != interceptor && ((TypeElement) element).getInterfaces().contains(iInterceptor); }
end~
2.2.4.4 动态生成类 2.2.4.4.1 模版信息 最终生成的 java 文件名为:
1 ARouter$$Interceptors$${moduleName}.java
最终生成的模版类信息为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 package com.alibaba.android.arouter.routes;import com.alibaba.android.arouter.facade.template.IInterceptor;import com.alibaba.android.arouter.facade.template.IInterceptorGroup;import java.lang.Class;import java.lang.Integer;import java.lang.Override;import java.util.Map;... ... ... public class ARouter $$Interceptors $$$ {moduleName} implements IInterceptorGroup { @Override public void loadInto (Map<Integer, Class<? extends ITollgate>> interceptors) { interceptors.put(${priority}, ${InterceptorName}.class); } }
可以看到,对于 Interceptor,ARouter 也是采取分组管理的方式:
以 module 为组,组名为 ARouter$$Interceptors$${moduleName}
;
2.2.4.4.2 举个栗子 2.2.4.4.2.1 实例代码 我们自定义了一个拦截器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 package com.lishuaiqi.test;import android.content.Context;import com.alibaba.android.arouter.facade.Postcard;import com.alibaba.android.arouter.facade.annotation.Interceptor;import com.alibaba.android.arouter.facade.callback.InterceptorCallback;import com.alibaba.android.arouter.facade.template.IInterceptor;@Interceptor (priority = 8 , name = "测试用拦截器" )public class TestInterceptor implements IInterceptor { @Override public void process (Postcard postcard, InterceptorCallback callback) { } @Override public void init (Context context) { } }
2.2.4.4.2.2 动态代码 看看最终的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package com.alibaba.android.arouter.routes;import com.alibaba.android.arouter.facade.template.IInterceptor;import com.alibaba.android.arouter.facade.template.IInterceptorGroup;import com.lishuaiqi.test.TestInterceptor;import java.lang.Class;import java.lang.Integer;import java.lang.Override;import java.util.Map;public class ARouter $$Interceptors $$Coolqi implements IInterceptorGroup { @Override public void loadInto (Map<Integer, Class<? extends IInterceptor>> interceptors) { interceptors.put(8 , TestInterceptor.class); } }
2.3 utils 该 package 下包含了一些工具类:
2.3.1 Logger 用于打印 log 信息,调试使用;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 public class Logger { private Messager msg; public Logger (Messager messager) { msg = messager; } public void info (CharSequence info) { if (StringUtils.isNotEmpty(info)) { msg.printMessage(Diagnostic.Kind.NOTE, Consts.PREFIX_OF_LOGGER + info); } } public void error (CharSequence error) { if (StringUtils.isNotEmpty(error)) { msg.printMessage(Diagnostic.Kind.ERROR, Consts.PREFIX_OF_LOGGER + "An exception is encountered, [" + error + "]" ); } } public void error (Throwable error) { if (null != error) { msg.printMessage(Diagnostic.Kind.ERROR, Consts.PREFIX_OF_LOGGER + "An exception is encountered, [" + error.getMessage() + "]" + "\n" + formatStackTrace(error.getStackTrace())); } } public void warning (CharSequence warning) { if (StringUtils.isNotEmpty(warning)) { msg.printMessage(Diagnostic.Kind.WARNING, Consts.PREFIX_OF_LOGGER + warning); } } private String formatStackTrace (StackTraceElement[] stackTrace) { StringBuilder sb = new StringBuilder(); for (StackTraceElement element : stackTrace) { sb.append(" at " ).append(element.toString()); sb.append("\n" ); } return sb.toString(); }
方法都比较简单,就不多说了。
2.3.2 TypeUtils 该类是一个类型工具类,主要用于获取元素的类型,并对类型做一个转换;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 public class TypeUtils { private Types types; private TypeMirror parcelableType; private TypeMirror serializableType; public TypeUtils (Types types, Elements elements) { this .types = types; parcelableType = elements.getTypeElement(PARCELABLE).asType(); serializableType = elements.getTypeElement(SERIALIZABLE).asType(); } public int typeExchange (Element element) { TypeMirror typeMirror = element.asType(); if (typeMirror.getKind().isPrimitive()) { return element.asType().getKind().ordinal(); } switch (typeMirror.toString()) { case BYTE: return TypeKind.BYTE.ordinal(); case SHORT: return TypeKind.SHORT.ordinal(); case INTEGER: return TypeKind.INT.ordinal(); case LONG: return TypeKind.LONG.ordinal(); case FLOAT: return TypeKind.FLOAT.ordinal(); case DOUBEL: return TypeKind.DOUBLE.ordinal(); case BOOLEAN: return TypeKind.BOOLEAN.ordinal(); case CHAR: return TypeKind.CHAR.ordinal(); case STRING: return TypeKind.STRING.ordinal(); default : if (types.isSubtype(typeMirror, parcelableType)) { return TypeKind.PARCELABLE.ordinal(); } else if (types.isSubtype(typeMirror, serializableType)) { return TypeKind.SERIALIZABLE.ordinal(); } else { return TypeKind.OBJECT.ordinal(); } } }
TypeKind 前面有分析过,其是一个枚举类!
2.3.3 Consts 用于保存一些核心的常量,下面来看看核心的常量。
2.3.3.1 Log 打印相关 这些是和 log 打印相关的,比较简单:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public static final String PROJECT = "ARouter" ; public static final String TAG = PROJECT + "::" ;static final String PREFIX_OF_LOGGER = PROJECT + "::Compiler " ;public static final String NO_MODULE_NAME_TIPS = "These no module name, at 'build.gradle', like :\n" + "android {\n" + " defaultConfig {\n" + " ...\n" + " javaCompileOptions {\n" + " annotationProcessorOptions {\n" + " arguments = [AROUTER_MODULE_NAME: project.getName()]\n" + " }\n" + " }\n" + " }\n" + "}\n" ;
不多说!
2.3.3.2 Gradle 配置相关 这些是和 gradle 配置相关的机制:
1 2 3 public static final String KEY_MODULE_NAME = "AROUTER_MODULE_NAME" ;public static final String KEY_GENERATE_DOC_NAME = "AROUTER_GENERATE_DOC" ;public static final String VALUE_ENABLE = "enable" ;
这个前面有说过,通过 gradle 配置;
2.3.3.3 系统核心类 这些是和 Android 系统的一些核心类有关,也是 ARouter 能够注解处理的类:
1 2 3 4 5 public static final String ACTIVITY = "android.app.Activity" ;public static final String FRAGMENT = "android.app.Fragment" ;public static final String FRAGMENT_V4 = "android.support.v4.app.Fragment" ;public static final String SERVICE = "android.app.Service" ;public static final String PARCELABLE = "android.os.Parcelable" ;
可以看到,都是系统类的全限定名;
2.3.3.4 注解类型 这些是和 ARouter 的注解相关的常量:
1 2 3 4 private static final String FACADE_PACKAGE = "com.alibaba.android.arouter.facade" ; public static final String ANNOTATION_TYPE_INTECEPTOR = FACADE_PACKAGE + ".annotation.Interceptor" ;public static final String ANNOTATION_TYPE_ROUTE = FACADE_PACKAGE + ".annotation.Route" ;public static final String ANNOTATION_TYPE_AUTOWIRED = FACADE_PACKAGE + ".annotation.Autowired" ;
可以看到,都是注解的全限定名;
2.3.3.5 核心接口和类 这些是和 ARouter 提供的一些核心接口:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 private static final String FACADE_PACKAGE = "com.alibaba.android.arouter.facade" ;private static final String TEMPLATE_PACKAGE = ".template" ;private static final String SERVICE_PACKAGE = ".service" ;private static final String MODEL_PACKAGE = ".model" ;public static final String IPROVIDER = FACADE_PACKAGE + TEMPLATE_PACKAGE + ".IProvider" ;public static final String IPROVIDER_GROUP = FACADE_PACKAGE + TEMPLATE_PACKAGE + ".IProviderGroup" ;public static final String IINTERCEPTOR = FACADE_PACKAGE + TEMPLATE_PACKAGE + ".IInterceptor" ;public static final String IINTERCEPTOR_GROUP = FACADE_PACKAGE + TEMPLATE_PACKAGE + ".IInterceptorGroup" ;public static final String ITROUTE_ROOT = FACADE_PACKAGE + TEMPLATE_PACKAGE + ".IRouteRoot" ;public static final String IROUTE_GROUP = FACADE_PACKAGE + TEMPLATE_PACKAGE + ".IRouteGroup" ;public static final String ISYRINGE = FACADE_PACKAGE + TEMPLATE_PACKAGE + ".ISyringe" ;public static final String JSON_SERVICE = FACADE_PACKAGE + SERVICE_PACKAGE + ".SerializationService" ;public static final String TYPE_WRAPPER = FACADE_PACKAGE + MODEL_PACKAGE + ".TypeWrapper" ;
同样的,也是一些全限定名;
ARouter 的拦截器需要实现 IInterceptor 接口,服务需要实现 IProvider 接口;
同时,由于 ARouter 是分组管理的,所以拦截器和服务又会属于不同的组:拦截器组需要实现 IInterceptorGroup 接口,服务组需要实现 IProviderGroup 组;
对于跳转来说,也会有分组,跳转组需要实现 IRouteGroup,而所有的跳转组属于一个 root:IRouteRoot
2.3.3.6 动态生成类 下面 这些是和动态生成的类相关的:
1 2 3 4 5 6 7 8 9 public static final String SEPARATOR = "$$" ;public static final String PROJECT = "ARouter" ;public static final String METHOD_LOAD_INTO = "loadInto" ;public static final String METHOD_INJECT = "inject" ;public static final String NAME_OF_ROOT = PROJECT + SEPARATOR + "Root" ; public static final String NAME_OF_PROVIDER = PROJECT + SEPARATOR + "Providers" ; public static final String NAME_OF_GROUP = PROJECT + SEPARATOR + "Group" + SEPARATOR; public static final String NAME_OF_INTERCEPTOR = PROJECT + SEPARATOR + "Interceptors" ; public static final String NAME_OF_AUTOWIRED = SEPARATOR + PROJECT + SEPARATOR + "Autowired" ;
动态生成类的类名是通过 “$$” 将关键字拼接起来!
1 2 public static final String PACKAGE_OF_GENERATE_FILE = "com.alibaba.android.arouter.routes" ;public static final String PACKAGE_OF_GENERATE_DOCS = "com.alibaba.android.arouter.docs" ;
ARouter 会通过 javapoet 来动态生成对应的类,我们在分析 processor 的过程中就会看到。
3 总结 本篇文章分析了 arouter-compiler 模块的架构,arouter 内置的三种注解处理器,以及 arouter 注解的处理,动态类的生成。
好累~
后续上流程图吧~~对于个人收获也是很大的~~至少会自定义注解~~至少会动态生成代码了~~