ARouter源码分析
源码看过好几遍了,但是总是会忘记,特此记录下
先从注解处理器开始
BaseProcessor是其他三个注解处理器的抽象类,子类去实现process方法。
在其中的init方法中会获取我们的module模块中.gradle文件填写的AROUTER_MODULE_NAME对应的value。如果处理过的moduleName的值是空会抛出异常
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."); }
然后就是初始化一些工具
mFiler = processingEnv.getFiler(); types = processingEnv.getTypeUtils(); elementUtils = processingEnv.getElementUtils(); typeUtils = new TypeUtils(types, elementUtils); logger = new Logger(processingEnv.getMessager());
RouteProcessor用来处理Route这个注解
//其实这个key是我们设置的group组名,缺省情况下是path的第一个单词,并不是每个module下的路由集合,
//例如:一个module下我们的2个Route值分别设置了group="group1"和 group="group2",那么这个Map中就会有2个值分别存储
//group1分组下的路由集合和group2下面的路由集合,也会为我们生成2个类设置。后面代码会解析
private Map<String, Set<RouteMeta>> groupMap = new HashMap<>(); // ModuleName and routeMeta. 这个官方的注释有问题
//这个其实是一个索引表,key是组名,value是上面注释中的生成的类名,也就是通过这个key就能找到上面的路由集合。这个是每一个module对应一个类。
private Map<String, String> rootMap = new TreeMap<>();
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { if (CollectionUtils.isNotEmpty(annotations)) {
//扫描项目拿到所有带Route注解的元素 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(Set<? extends Element> routeElements)方法
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();
// Interface of ARouter
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);
获取类元素对应的Type类型 关于type和Element参考:https://www.jianshu.com/p/899063e8452e
/*
Build input type, format as :
```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)
);
利用javaport创建Map<String, Class<? extends IRouteGroup>> 和 Map<String, RouteMeta>方法这个参数类型
ParameterSpec rootParamSpec = ParameterSpec.builder(inputMapTypeOfRoot, "routes").build();
ParameterSpec groupParamSpec = ParameterSpec.builder(inputMapTypeOfGroup, "atlas").build();
ParameterSpec providerParamSpec = ParameterSpec.builder(inputMapTypeOfGroup, "providers").build();
到此就创建了
Map<String, Class<? extends IRouteGroup>> routes 和 Map<String, RouteMeta> atlas 以及 Map<String, RouteMeta> providers完整参数
/*
Build method : 'loadInto'
*/
MethodSpec.Builder loadIntoMethodOfRootBuilder = MethodSpec.methodBuilder(METHOD_LOAD_INTO)
.addAnnotation(Override.class)
.addModifiers(PUBLIC)
.addParameter(rootParamSpec);
创建方法:loadIntoMethodOfRootBuilder <--> loadInto(Map<String, Class<? extends IRouteGroup>> routes) 后面创建ARouter$$Root$$moduleName类使用
for (Element element : routeElements) { TypeMirror tm = element.asType(); Route route = element.getAnnotation(Route.class); RouteMeta routeMeta; // Activity or Fragment if (types.isSubtype(tm, type_Activity) || types.isSubtype(tm, fragmentTm) || types.isSubtype(tm, fragmentTmV4)) { // Get all fields annotation by @Autowired
//带Autowirde注解属性的名称和类型(name,String类型)(sex,boolean属性)后面的Integer是枚举类型 Map<String, Integer> paramsType = new HashMap<>();
Map<String, Autowired> injectConfig = new HashMap<>();
//这个用来处理子级中带Autowirde注解 injectParamCollector(element, paramsType, injectConfig); if (types.isSubtype(tm, type_Activity)) { // Activity logger.info(">>> Found activity route: " + tm.toString() + " <<<"); routeMeta = new RouteMeta(route, element, RouteType.ACTIVITY, paramsType); } else { // Fragment logger.info(">>> Found fragment route: " + tm.toString() + " <<<"); routeMeta = new RouteMeta(route, element, RouteType.parse(FRAGMENT), paramsType); } //Activity或者fragment中的带Autowird的属性也会放进路由中 routeMeta.setInjectConfig(injectConfig); } else if (types.isSubtype(tm, iProvider)) { // IProvider logger.info(">>> Found provider route: " + tm.toString() + " <<<"); routeMeta = new RouteMeta(route, element, RouteType.PROVIDER, null); } else if (types.isSubtype(tm, type_Service)) { // Service logger.info(">>> Found service route: " + tm.toString() + " <<<"); routeMeta = new RouteMeta(route, element, RouteType.parse(SERVICE), null); } else { throw new RuntimeException("The @Route is marked on unsupported class, look at [" + tm.toString() + "]."); } //验证path的准确性和填充路由表groupMap categories(routeMeta); }
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);
//把路由表和相应的group对应
groupMap.put(routeMete.getGroup(), routeMetaSet);
} else {
//如果已经存在组了,就直接添加到路由表中
routeMetas.add(routeMete);
}
} else {
logger.warning(">>> Route meta verify error, group is " + routeMete.getGroup() + " <<<");
}
}
//验证path的准确性
private boolean routeVerify(RouteMeta meta) {
String path = meta.getPath();
//如果path是空或者path没有以"/"开始验证失败
if (StringUtils.isEmpty(path) || !path.startsWith("/")) { // The path must be start with '/' and not empty!
return false;
}
//group缺省情况用path中的第一个单词作为group值
if (StringUtils.isEmpty(meta.getGroup())) { // Use default group(the first word in path)
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;
}
经过上面的方法之后groupMap就被赋值成功了,下面就是类的生成了。
MethodSpec.Builder loadIntoMethodOfProviderBuilder = MethodSpec.methodBuilder(METHOD_LOAD_INTO)
.addAnnotation(Override.class)
.addModifiers(PUBLIC)
.addParameter(providerParamSpec);
创建 loadIntoMethodOfProviderBuilder <--->loadInto(Map<String, Class<? extends IRouteGroup>> providers )后面创建ARouter$$Providers$$moduleName类使用
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<>(); // Build group method body 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: // Need cache provider's super class List<? extends TypeMirror> interfaces = ((TypeElement) routeMeta.getRawType()).getInterfaces(); for (TypeMirror tm : interfaces) { routeDoc.addPrototype(tm.toString()); if (types.isSameType(tm, iProvider)) { // Its implements iProvider interface himself. // This interface extend the IProvider, so it can be used for mark provider 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)) { // This interface extend the IProvider, so it can be used for mark provider loadIntoMethodOfProviderBuilder.addStatement( "providers.put($S, $T.build($T." + routeMeta.getType() + ", $T.class, $S, $S, null, " + routeMeta.getPriority() + ", " + routeMeta.getExtra() + "))", tm.toString(), // So stupid, will duplicate only save class name. routeMetaCn, routeTypeCn, className, routeMeta.getPath(), routeMeta.getGroup()); } } break; default: break; } // Make map body for paramsType 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); } // 有几个组就生成了几个类ARouter$$Group$$groupName 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 key是组名 value是上面生成的类名 rootMap.put(groupName, groupFileName); docSource.put(groupName, routeDocList); }
经过这个遍历系统为我们生成了
public class ARouter$$Group$$组名 implement IRooteGroup{
public void loadInto(Map<String,RouteMata> atlas){
atlas.put("/order/OrderActivity", RouteMeta 对象)
atlas.put("/order/OrderDetailActivity", RouteMeta 对象)
当外部调用这个方法的时候就会得到整个路由信息了
}
}
if (MapUtils.isNotEmpty(rootMap)) {
// Generate root meta by group name, it must be generated before root, then I can find out the class of group.
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()));
}
}
// Output route doc
if (generateDoc) {
docWriter.append(JSON.toJSONString(docSource, SerializerFeature.PrettyFormat));
docWriter.flush();
docWriter.close();
}
// 创建ARouter$$Providers$$模块名这个类 loadInto 方法中的Map key是整个类名 值是RouteMeta
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 + " <<<");
// 创建Arouter$$Route$$模块名 key是组名 值是 Arouter$$Group$$组名 对应的class
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);
经过上面的操作就生成了
public class ARouter$$Providers$$modulejava implements IProviderGroup {
@Override
public void loadInto(Map<String, RouteMeta> providers) {
providers.put("com.alibaba.android.arouter.demo.service.HelloService", RouteMeta.build(RouteType.PROVIDER, HelloServiceImpl.class, "/yourservicegroupname/hello", "yourservicegroupname", null, -1, -2147483648));
providers.put("com.alibaba.android.arouter.facade.service.SerializationService", RouteMeta.build(RouteType.PROVIDER, JsonServiceImpl.class, "/yourservicegroupname/json", "yourservicegroupname", null, -1, -2147483648));
providers.put("com.alibaba.android.arouter.demo.module1.testservice.SingleService", RouteMeta.build(RouteType.PROVIDER, SingleService.class, "/yourservicegroupname/single", "yourservicegroupname", null, -1, -2147483648));
}
}
public class ARouter$$Root$$modulejava implements IRouteRoot {
@Override
public void loadInto(Map<String, Class<? extends IRouteGroup>> routes) {
routes.put("m2", ARouter$$Group$$m2.class);
routes.put("module", ARouter$$Group$$module.class);
routes.put("test", ARouter$$Group$$test.class);
routes.put("yourservicegroupname", ARouter$$Group$$yourservicegroupname.class);
}
}
至此我们也能发现ARouter$$Root$$模块名 和 ARouter$$Providers$$模块名 是有几个模块就会创建几个类,但是ARouter$$Group$$组名则是有几个组就创建几个类
并且ARouter$$Group$$组名这个类里面也会存储provider路由信息,ARouter$$Providers$$模块名也会存储provider信息。也就是说我们既可以通过path查找provider信息
也可以通过全类名查找provider信息。
至此 Route这个注解的功能就分析完毕,等待应用程序注册的时候调用我们上面创建类的方法,把数据存储到仓库中即可
Autowired这个注解比较简单就是利用反射调用我们的getIntent.get方法去赋值。
Interceptor这个注解用来帮助我们生成ARouter$$Interceptors$$modulejava这样的类
public class ARouter$$Interceptors$$modulejava implements IInterceptorGroup {
@Override
public void loadInto(Map<Integer, Class<? extends IInterceptor>> interceptors) {
//key 是优先级 值是我们添加的拦截器的class
interceptors.put(7, Test1Interceptor.class);
interceptors.put(90, TestInterceptor90.class);
}
}
当我们调用ARouter.init(application)的时候
1.启动线程池扫描包下面的class对象得到类的集合 有缓存不用每次都扫描
2.解析类集合如果是以ARouter$$Root开头的类利用class.forName获取IRouterRoot对象,调用loadInto方法把里面的Map赋值给数据仓库中的Map
填充:WareHouse中的Map<String,class<? extends IRoteGroup>> groupsIndex
3.以ARoute$$Interceptors开头就调用IInterceptors的loadInto方法填充WareHouse中的Map<Integer,class<? extends IRoteGroup>>interceptorsIndex
4.以ARoute$$Providers开头的就调用IProvidersGroup的loadInto方法填充WareHouse中的Map<String,RouteMeta>providersIndex
这个时候肯定会有疑问:我们生成的ARouter$$Group$$组名中的loadInto方法怎么没有调用?
for (String className : routerMap) {
if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_ROOT)) {
// This one of root elements, load root.
((IRouteRoot) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.groupsIndex);
} else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_INTERCEPTORS)) {
// Load interceptorMeta
((IInterceptorGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.interceptorsIndex);
} else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_PROVIDERS)) {
// Load providerIndex
((IProviderGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.providersIndex);
}
}
初始化完成后调用了下面的这个方法
static void afterInit() {
// Trigger interceptor init, use byName.
interceptorService = (InterceptorService) ARouter.getInstance().build("/arouter/service/interceptor").navigation();
}
protected Postcard build(String path) {
if (TextUtils.isEmpty(path)) {
throw new HandlerException(Consts.TAG + "Parameter is invalid!");
} else {
//给我们暴露了一个可以预处理事情的PathReplaceService这个IProvider接口,如果我们实现了这个接口就可以提前做一些事情主要是路径替换--一个hook点吧
PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);
if (null != pService) {
path = pService.forString(path);
}
return build(path, extractGroup(path), true);
}
}
@Route(path = "/arouter/service/interceptor")
public class InterceptorServiceImpl implements InterceptorService 这个系统的拦截器里面利用线程池处理我们自己的拦截器
protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) { //这个同样是一个预处理点如果我们设置了这个provider,就可以截获并取消这个跳转
PretreatmentService pretreatmentService = ARouter.getInstance().navigation(PretreatmentService.class); if (null != pretreatmentService && !pretreatmentService.onPretreatment(context, postcard)) { // Pretreatment failed, navigation canceled. return null; } // Set context to postcard. postcard.setContext(null == context ? mContext : context); try {
//这个里面完成了对postcard信息的完善:路径class 是否是绿色通道等,数据仓库里面剩余map的填充 LogisticsCenter.completion(postcard); } catch (NoRouteFoundException ex) { logger.warning(Consts.TAG, ex.getMessage()); if (debuggable()) { // Show friendly tips for user. runInMainThread(new Runnable() { @Override public void run() { Toast.makeText(mContext, "There's no route matched!\n" + " Path = [" + postcard.getPath() + "]\n" + " Group = [" + postcard.getGroup() + "]", Toast.LENGTH_LONG).show(); } }); } //异常发生后会回调我们的丢失方法 if (null != callback) { callback.onLost(postcard); } else { // No callback for this invoke, then we use the global degrade service.
//如果没有设置回调还可以通过实现下面的接口来实现回调,这个是全局的
DegradeService degradeService = ARouter.getInstance().navigation(DegradeService.class); if (null != degradeService) { degradeService.onLost(context, postcard); } } return null; } if (null != callback) { callback.onFound(postcard); } //只有非绿色通道才可以进行拦截处理 if (!postcard.isGreenChannel()) { // It must be run in async thread, maybe interceptor cost too mush time made ANR.
//这个里面是开启线程池按照优先级调用我们的拦截器 interceptorService.doInterceptions(postcard, new InterceptorCallback() { /** * Continue process * * @param postcard route meta */ @Override public void onContinue(Postcard postcard) { _navigation(postcard, requestCode, callback); } /** * Interrupt process, pipeline will be destory when this method called. * * @param exception Reson of interrupt. */ @Override public void onInterrupt(Throwable exception) { if (null != callback) { callback.onInterrupt(postcard); } logger.info(Consts.TAG, "Navigation failed, termination by interceptor : " + exception.getMessage()); } }); } else {
//看下真正的路由实现 return _navigation(postcard, requestCode, callback); } return null; }
private Object _navigation(final Postcard postcard, final int requestCode, final NavigationCallback callback) { final Context currentContext = postcard.getContext(); switch (postcard.getType()) { case ACTIVITY: // Build intent final Intent intent = new Intent(currentContext, postcard.getDestination()); intent.putExtras(postcard.getExtras()); // Set flags. int flags = postcard.getFlags(); if (0 != flags) { intent.setFlags(flags); } // Non activity, need FLAG_ACTIVITY_NEW_TASK if (!(currentContext instanceof Activity)) { intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); } // Set Actions String action = postcard.getAction(); if (!TextUtils.isEmpty(action)) { intent.setAction(action); } // Navigation in main looper. runInMainThread(new Runnable() { @Override public void run() { startActivity(requestCode, currentContext, intent, postcard, callback); } }); break; case PROVIDER: return postcard.getProvider(); case BOARDCAST: case CONTENT_PROVIDER: case FRAGMENT: Class<?> fragmentMeta = postcard.getDestination(); try { Object instance = fragmentMeta.getConstructor().newInstance(); if (instance instanceof Fragment) { ((Fragment) instance).setArguments(postcard.getExtras()); } else if (instance instanceof android.support.v4.app.Fragment) { ((android.support.v4.app.Fragment) instance).setArguments(postcard.getExtras()); } return instance; } catch (Exception ex) { logger.error(Consts.TAG, "Fetch fragment instance error, " + TextUtils.formatStackTrace(ex.getStackTrace())); } case METHOD: case SERVICE: default: return null; } return null; }