组件化知识梳理(2) - Arouter 源码分析之 Complier SDK

组件化知识梳理目录

组件化知识梳理(1) - Arouter 的基本使用
组件化知识梳理(2) - Arouter 源码分析之 Complier SDK
组件化知识梳理(3) - Arouter 源码分析之运行时 SDK

一、概述

Arouter的源码 https://github.com/alibaba/ARouter 当中,最主要的就是下面这三个部分:注解arouter-annotation、运行时arouter-api和编译时arouter-complier

Arouter 源码

1.1 注解 arouter-annotation

arouter-annotation定义了我们之前在 组件化知识梳理(1) - Arouter 的基本使用
中使用过的注解:

  • Router:路径路由,2.3.1
  • intercepter:拦截器,2.3.6
  • AutoWired:依赖注入,2.3.7
注解 arouter-annotation

1.2 编译时 arouter-complier

arouter-complier的内部包含了三个注解处理器,用于处理1.1中使用的三种注解,它们都继承于AbstractProcessor,其原理和 Java&Android 基础知识梳理(1) - 注解 中介绍的 编译时处理注解 原理是相同的,最终目的就是通过这三个注解处理器,在 编译期 扫描被标注的文件,然后按照不同的源文件进行分类,按照 固定的命名格式生成映射文件

编译时 arouter-complier

以第一篇文章中看到的module-home模块为例,其会通过解析注解创建下面的.java映射文件,并打包到最终的apk当中:

module-home 创建的映射文件

module-other 创建的映射文件
module-store 创建的映射文件
lib-base 创建的映射文件

1.3 运行时 arouter-api

运行时arouter-api所包含的组件可以用下面这张图来表示。
[图片上传失败...(image-9d4212-1523552507081)]
从上之下分为四层:

  • Launcher层,包含了开发者可以直接使用的API,例如Arouter.getInstance()...

    Launcher 层

  • Frossard层,包含了三个部分:

    • Service,从意义上讲是将一定的功能和组件封装成接口,并对外提供能力。
    • Callback,回调接口。
    • Template,用于处理在编译期SDK生成的映射文件,这些映射文件会按照Template组件中提供的模板来生成,这样按照一定规则和约束生成的映射文件也方便ARouter在运行时进行读取。
      Frossard 层
  • SDK内部实现:

    • Ware House,主要存储了ARouter在运行期间加载的一些配置文件以及映射关系。
    • Thread,提供异步加载的线程池。
    • Class Tool,解决不同类型的APK兼容问题。
      SDK 内部实现
  • Logistics Center,物流中心,整个SDK的流转以及内部调用都会下沉到这一层,并会按照功能模块进行划分。

    Logistics Center

二、arouter-complier 详解

今天这篇文章,我们就来分析编译时的arouter-complier的实现,看一下映射文件是如何生成的。

2.1 基础知识

按照注解的处理时期,分为两种类型:运行时和编译时,运行时注解处理会引起性能问题,编译时注解依赖APT(Annotation Processing Tools)实现,其原理是在类、函数、字段上添加注解,在编译时,编译器会去检查AbstractProcessor的子类,并调用它实现的process函数,然后将添加了注解的所有元素都传递到process函数中,使得开发人员可以在编译期进行处理,主要就是生成新的Java类。

关于编译时注解的处理,我们在 Java&Android 基础知识梳理(1) - 注解 文中用一个详细的例子说明了,大家可以看一下,这里我们简要说一下在代码中用到的类的作用:

  • ProcessingEnvironment:用于提供实用的工具类,主要是ElementsTypesFiler这三个。
    • Elements:用来处理Element的工具类,源码中的每个部分都是Element的一个特定类型,其代码程序中的元素,例如包、类、方法,每一个元素代表一个静态的,语言级别的结构,Element是一个interface,它定义了如下的接口:

      Element 定义的接口

      根据类、成员变量等不同,有如下的继承接口 & 实现类:
      Element 的实现类

    • Types:用来处理TypeMirror的工具类。从Element的实现类中,例如TypeElement,我们可以获取类的名称,但你不能获取类的信息,可以通过element.asType()来获取一个ElementTypeMirror,然后获取类的信息。

    • Filer:用来创建文件。

我们在 创建映射文件 的时候,包括以下几步,后一步的结果依赖于前一步:

  • 函数形参的类型,使用ParameterizedTypeName
  • 函数形参的类型 & 名称,使用ParameterSpec
  • 函数的声明,使用MethodSpec.Builder
  • 类的声明,使用JavaFile.builder,最后调用JavaFilewriteTo(mFiler)方法写入到磁盘当中,这里的mFiler就是通过ProcessingEnvironment获取到的。

2.2 @Route 注解的解析

下面是对于RouteProcessor的 解析,详细的可以看注释里面的说明。

/**
 * A processor used for find route.
 *
 * @author Alex <a href="mailto:zhilong.liu@aliyun.com">Contact me.</a>
 * @version 1.0
 * @since 16/8/15 下午10:08
 */
@AutoService(Processor.class)
@SupportedOptions(KEY_MODULE_NAME)
@SupportedSourceVersion(SourceVersion.RELEASE_7)
@SupportedAnnotationTypes({ANNOTATION_TYPE_ROUTE, ANNOTATION_TYPE_AUTOWIRED})
public class RouteProcessor extends AbstractProcessor {

    /**
     * 以组为 key,value 对应于该组下解析出的所有注解信息,Set 的实现为 TreeSet,会根据 path 来进行排序。
     */
    private Map<String, Set<RouteMeta>> groupMap = new HashMap<>();

    /**
     * 以根节点为 key,value 对应于创建的文件。
     */
    private Map<String, String> rootMap = new TreeMap<>();
    private Filer mFiler;
    private Logger logger;
    private Types types;
    private Elements elements;
    private TypeUtils typeUtils;
    private String moduleName = null;
    private TypeMirror iProvider = null;

    /**
     * 通过 ProcessingEnvironment 初始化后面需要使用到的工具类,例如 Filer,Types 和 Elements。
     * @param processingEnv 提供解析注解所需的工具类。
     */
    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);

        //Filer:用于创建 Java 文件的工具类。
        mFiler = processingEnv.getFiler();
        //Types:用于操作类型的工具类。
        types = processingEnv.getTypeUtils();
        //Elements:用于处理 Element 的工具类。
        elements = processingEnv.getElementUtils();

        //将两个工具类进行封装。
        typeUtils = new TypeUtils(types, elements);
        //日志工具类。
        logger = new Logger(processingEnv.getMessager());

        //解析我们在 android 节点下配置的 moduleName,其为对应模块的名字。
        Map<String, String> options = processingEnv.getOptions();
        if (MapUtils.isNotEmpty(options)) {
            moduleName = options.get(KEY_MODULE_NAME);
        }

        //对 moduleName 进行处理。
        if (StringUtils.isNotEmpty(moduleName)) {
            moduleName = moduleName.replaceAll("[^0-9a-zA-Z_]+", "");
            logger.info("The user has configuration the module name, it was [" + moduleName + "]");
        //如果没有配置 moduleName,那么会抛出异常。
        } else {
            logger.error("These no module name, at 'build.gradle', like :\n" +
                    "apt {\n" +
                    "    arguments {\n" +
                    "        moduleName project.getName();\n" +
                    "    }\n" +
                    "}\n");
            throw new RuntimeException("ARouter::Compiler >>> No module name, for more information, look at gradle log.");
        }

        //获取 IProvider 的 TypeMirror,它包含了 IProvider 的所有信息。
        iProvider = elements.getTypeElement(Consts.IPROVIDER).asType();

        logger.info(">>> RouteProcessor init. <<<");
    }

    /**
     * {@inheritDoc}
     *
     * @param annotations
     * @param roundEnv
     */
    @Override
    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;
    }

    private void parseRoutes(Set<? extends Element> routeElements) throws IOException {
        if (CollectionUtils.isNotEmpty(routeElements)) {

            logger.info(">>> Found routes, size is " + routeElements.size() + " <<<");
            //清空信息。
            rootMap.clear();

            //1.获得 Activity、Service、Fragment 和 FragmentV4 的信息,这些是定义在 Android SDK 当中的。
            TypeMirror type_Activity = elements.getTypeElement(ACTIVITY).asType();
            TypeMirror type_Service = elements.getTypeElement(SERVICE).asType();
            TypeMirror fragmentTm = elements.getTypeElement(FRAGMENT).asType();
            TypeMirror fragmentTmV4 = elements.getTypeElement(Consts.FRAGMENT_V4).asType();

            //2.获得 IRouteGroup 和 IProviderGroup 的信息,这些接口是定义在 arouter-api 当中的模板。
            TypeElement type_IRouteGroup = elements.getTypeElement(IROUTE_GROUP);
            TypeElement type_IProviderGroup = elements.getTypeElement(IPROVIDER_GROUP);

            //3.RouteMeta 和 RouteType 的信息。
            ClassName routeMetaCn = ClassName.get(RouteMeta.class);
            ClassName routeTypeCn = ClassName.get(RouteType.class);

            //4. 定义函数形参的类型为 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))
                    )
            );

            //5. 定义函数形参的类型为 Map<String, RouteMeta>。
            ParameterizedTypeName inputMapTypeOfGroup = ParameterizedTypeName.get(
                    ClassName.get(Map.class),
                    ClassName.get(String.class),
                    ClassName.get(RouteMeta.class)
            );

            //6. 定义函数的形参类型 & 形参名字。
            //6.1 Map<String, Class<? extends IRouteGroup>> routes
            ParameterSpec rootParamSpec = ParameterSpec.builder(inputMapTypeOfRoot, "routes").build();
            //6.2 Map<String, RouteMeta> atlas
            ParameterSpec groupParamSpec = ParameterSpec.builder(inputMapTypeOfGroup, "atlas").build();
            //6.3 Map<String, RouteMeta> providers
            ParameterSpec providerParamSpec = ParameterSpec.builder(inputMapTypeOfGroup, "providers").build();

            //7.定义函数的声明为 public void loadInto(Map<String, Class<? extends IRouteGroup>> routes)。
            MethodSpec.Builder loadIntoMethodOfRootBuilder = MethodSpec.methodBuilder(METHOD_LOAD_INTO)
                    .addAnnotation(Override.class)
                    .addModifiers(PUBLIC)
                    .addParameter(rootParamSpec);

            //8.遍历所有的被 @Route 注解的 Element
            for (Element element : routeElements) {
                //获得该元素的类型信息。
                TypeMirror tm = element.asType();
                //获得该元素的注解。
                Route route = element.getAnnotation(Route.class);
                RouteMeta routeMeta = null;
                //Activity 的子类。
                if (types.isSubtype(tm, type_Activity)) {
                    logger.info(">>> Found activity route: " + tm.toString() + " <<<");
                    Map<String, Integer> paramsType = new HashMap<>();
                    //获得其所有被 @Autowired 注解的成员变量。
                    for (Element field : element.getEnclosedElements()) {
                        //不处理 IProvider 的子类。
                        if (field.getKind().isField() && field.getAnnotation(Autowired.class) != null && !types.isSubtype(field.asType(), iProvider)) {
                            Autowired paramConfig = field.getAnnotation(Autowired.class);
                            //将所有被 @Autowired 注解的相关信息放到 map 当中。
                            paramsType.put(StringUtils.isEmpty(paramConfig.name()) ? field.getSimpleName().toString() : paramConfig.name(), typeUtils.typeExchange(field));
                        }
                    }
                    routeMeta = new RouteMeta(route, element, RouteType.ACTIVITY, paramsType);
                //IProvider 的子类。
                } else if (types.isSubtype(tm, iProvider)) {
                    logger.info(">>> Found provider route: " + tm.toString() + " <<<");
                    routeMeta = new RouteMeta(route, element, RouteType.PROVIDER, null);
                //Service 的子类。
                } else if (types.isSubtype(tm, type_Service)) {
                    logger.info(">>> Found service route: " + tm.toString() + " <<<");
                    routeMeta = new RouteMeta(route, element, RouteType.parse(SERVICE), null);
                //Fragment 或者 FragmentV4 的子类。
                } 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() + "].");
                }
                //对其按 group 进行分组。
                categories(routeMeta);
            }

            //9. 定义函数的声明为 public void loadInto(Map<String, RouteMeta> providers)。
            MethodSpec.Builder loadIntoMethodOfProviderBuilder = MethodSpec.methodBuilder(METHOD_LOAD_INTO)
                    .addAnnotation(Override.class)
                    .addModifiers(PUBLIC)
                    .addParameter(providerParamSpec);

            //10. 创建 Java 源代码,遍历所有的 group。
            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 下所有的 RouteMeta。
                Set<RouteMeta> groupData = entry.getValue();

                for (RouteMeta routeMeta : groupData) {
                    switch (routeMeta.getType()) {
                        //填充函数体。
                        case PROVIDER:
                            List<? extends TypeMirror> interfaces = ((TypeElement) routeMeta.getRawType()).getInterfaces();
                            for (TypeMirror tm : interfaces) {
                                //IProvider。
                                if (types.isSameType(tm, iProvider)) {
                                    //添加 providers.put(..) 函数体。
                                    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());
                                //IProvider 的子类。
                                } else if (types.isSubtype(tm, iProvider)) {
                                    //添加 providers.put(..) 函数体。
                                    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;
                    }

                    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();
                    //填充函数体。
                    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());
                }

                //关键点1:每一个 group 创建一个 Java 文件,其类名为 Arouter$$Group$$组名,函数名为 public void loadInto(Map<String, RouteMeta> atlas)
                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);
            }

            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()));
                }
            }

            //关键点2:创建 Java 文件,类名为 Arouter$$Providers$$moduleName,函数名为 public void loadInto(Map<String, RouteMeta> providers),存放 PROVIDER 类型的节点。
            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 + " <<<");

            //关键点3:创建 Java 文件,类名为 Arouter$$Root$$moduleName,函数名为 public void loadInto(Map<String, Class<? extends IRouteGroup>> routes)
            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);

            logger.info(">>> Generated root, name is " + rootFileName + " <<<");
        }
    }

    /**
     * 对 @Route 注解的类进行分类。
     * @param routeMete
     */
    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() + " <<<");
        }
    }

    /**
     * 验证 RouteMeta,要求 @Route 指定的 name 不为空,并且要使用 / 作为开头。
     *
     * 并解析 RouteMeta 中的 group,默认是使用 / 后的第一个字段,如果指定了 group,那么就使用 group 的值。
     * @param meta
     * @return 验证正确。
     */
    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;
    }
}

大家注意看上面的三个关键点,其最终目的就是创建三个Java文件,对于第一章中的module-other,就是创建了下面三个文件:

module-other 创建的文件

  • ARouter$$Root$$ + 模块名,由于Arouter对于一个模块下的所有组件都是 采用分组加载 的机制,因此该文件存储的是组名,对应的value为该组下所有的组件。
/**
 * DO NOT EDIT THIS FILE!!! IT WAS GENERATED BY AROUTER. */
public class ARouter$$Root$$moduleother implements IRouteRoot {
  @Override
  public void loadInto(Map<String, Class<? extends IRouteGroup>> routes) {
    routes.put("other", ARouter$$Group$$other.class);
  }
}
  • ARouter$$Group$$ + 组名:对应该组下所有的组件,可以看到这里面包含了@Route中的path对应的组件的映射,这些信息都保存在RouteMeta当中。
/**
 * DO NOT EDIT THIS FILE!!! IT WAS GENERATED BY AROUTER. */
public class ARouter$$Group$$other implements IRouteGroup {
  @Override
  public void loadInto(Map<String, RouteMeta> atlas) {
    atlas.put("/other/event_bus", RouteMeta.build(RouteType.ACTIVITY, EventBusActivity.class, "/other/event_bus", "other", null, -1, -2147483648));
    atlas.put("/other/inject", RouteMeta.build(RouteType.ACTIVITY, InjectActivity.class, "/other/inject", "other", new java.util.HashMap<String, Integer>(){{put("inject_object", 10); put("inject_age", 3); }}, -1, -2147483648));
    atlas.put("/other/inter_middle", RouteMeta.build(RouteType.ACTIVITY, InterMiddleActivity.class, "/other/inter_middle", "other", null, -1, -2147483648));
    atlas.put("/other/inter_target", RouteMeta.build(RouteType.ACTIVITY, InterTargetActivity.class, "/other/inter_target", "other", null, -1, 2));
    atlas.put("/other/no_result", RouteMeta.build(RouteType.ACTIVITY, NoResultActivity.class, "/other/no_result", "other", null, -1, -2147483648));
    atlas.put("/other/result_server", RouteMeta.build(RouteType.ACTIVITY, ResultServerActivity.class, "/other/result_server", "other", null, -1, -2147483648));
  }
}
  • Arouter$$Providers$$ + 模块名:对应于该模块下所有IProvider的子类。
/**
 * DO NOT EDIT THIS FILE!!! IT WAS GENERATED BY AROUTER. */
public class ARouter$$Providers$$moduleother implements IProviderGroup {
  @Override
  public void loadInto(Map<String, RouteMeta> providers) {
  }
}

2.3 @Interceptor 注解的解析

@Interceptor注解的解析是通过InterceptorProcessor处理的,其说明如下面代码的注释,原理和2.2@Route相同,最终的目标也是创建Java文件。

@AutoService(Processor.class)
@SupportedOptions(KEY_MODULE_NAME)
@SupportedSourceVersion(SourceVersion.RELEASE_7)
@SupportedAnnotationTypes(ANNOTATION_TYPE_INTECEPTOR)
public class InterceptorProcessor extends AbstractProcessor {
    private Map<Integer, Element> interceptors = new TreeMap<>();
    private Filer mFiler;       // File util, write class file into disk.
    private Logger logger;
    private Elements elementUtil;
    private String moduleName = null;   // Module name, maybe its 'app' or others
    private TypeMirror iInterceptor = null;

    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        
        //工具类。
        mFiler = processingEnv.getFiler();                  // Generate class.
        elementUtil = processingEnv.getElementUtils();      // Get class meta.
        logger = new Logger(processingEnv.getMessager());   // Package the log utils.

        //获取模块名。
        Map<String, String> options = processingEnv.getOptions();
        if (MapUtils.isNotEmpty(options)) {
            moduleName = options.get(KEY_MODULE_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("These no module name, at 'build.gradle', like :\n" +
                    "apt {\n" +
                    "    arguments {\n" +
                    "        moduleName project.getName();\n" +
                    "    }\n" +
                    "}\n");
            throw new RuntimeException("ARouter::Compiler >>> No module name, for more information, look at gradle log.");
        }
        
        //获得 IInterceptor 的类信息。
        iInterceptor = elementUtil.getTypeElement(Consts.IINTERCEPTOR).asType();

        logger.info(">>> InterceptorProcessor init. <<<");
    }

    /**
     * 系统调用的处理类。
     * @param annotations 所有被注解的元素。
     * @param roundEnv 运行时环境。
     * @return 是否成功处理。
     */
    @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;
    }

    /**
     * 解析注解,创建 JavaFile
     * @param elements 所有被 @Interceptor 注解的元素。
     * @throws IOException 抛出异常。
     */
    private void parseInterceptors(Set<? extends Element> elements) throws IOException {
        if (CollectionUtils.isNotEmpty(elements)) {
            logger.info(">>> Found interceptors, size is " + elements.size() + " <<<");

            //1.遍历所有被 @Interceptor 注解的元素。
            for (Element element : elements) {
                //必须要实现 IInterceptor 接口。
                if (verify(element)) {
                    logger.info("A interceptor verify over, its " + element.asType());
                    Interceptor interceptor = element.getAnnotation(Interceptor.class);
                    //按照优先级作为 key,存储到 map 当中,必须要保证一个模块内的优先级不会重复,否则会抛出异常。
                    Element lastInterceptor = interceptors.get(interceptor.priority());
                    if (null != lastInterceptor) { // Added, throw exceptions
                        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 = elementUtil.getTypeElement(IINTERCEPTOR);
            TypeElement type_ITollgateGroup = elementUtil.getTypeElement(IINTERCEPTOR_GROUP);

            //2.函数形参的类型为 Map<Integer, Class<? extends IInterceptor>>
            ParameterizedTypeName inputMapTypeOfTollgate = ParameterizedTypeName.get(
                    ClassName.get(Map.class),
                    ClassName.get(Integer.class),
                    ParameterizedTypeName.get(
                            ClassName.get(Class.class),
                            WildcardTypeName.subtypeOf(ClassName.get(type_ITollgate))
                    )
            );

            //3.函数形参的类型 & 名字为 Map<Integer, Class<? extends IInterceptor>> interceptors
            ParameterSpec tollgateParamSpec = ParameterSpec.builder(inputMapTypeOfTollgate, "interceptors").build();

            //4.函数名为 loadInto
            MethodSpec.Builder loadIntoMethodOfTollgateBuilder = MethodSpec.methodBuilder(METHOD_LOAD_INTO)
                    .addAnnotation(Override.class)
                    .addModifiers(PUBLIC)
                    .addParameter(tollgateParamSpec);

            //5.利用前面遍历出来的列表,填充函数体。
            if (null != interceptors && interceptors.size() > 0) {
                // Build method body
                for (Map.Entry<Integer, Element> entry : interceptors.entrySet()) {
                    loadIntoMethodOfTollgateBuilder.addStatement("interceptors.put(" + entry.getKey() + ", $T.class)", ClassName.get((TypeElement) entry.getValue()));
                }
            }

            //6.关键点:写入 JavaFile,类名为 Arouter$$Interceptors$$moduleName
            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. <<<");
        }
    }

    /**
     * 验证,必须要保证实现了 IInterceptor 接口。
     * @param element 元素。
     * @return 验证陈宫。
     */
    private boolean verify(Element element) {
        Interceptor interceptor = element.getAnnotation(Interceptor.class);
        // It must be implement the interface IInterceptor and marked with annotation Interceptor.
        return null != interceptor && ((TypeElement) element).getInterfaces().contains(iInterceptor);
    }
}

最终会创建Java文件,例如我们在第一章的Demo中的lib-base,创建的文件为:

@Interceptor 注解创建的文件

其命名的规则为:Arouter$$Interceptors + 模块名

/**
 * DO NOT EDIT THIS FILE!!! IT WAS GENERATED BY AROUTER. */
public class ARouter$$Interceptors$$libbase implements IInterceptorGroup {
  @Override
  public void loadInto(Map<Integer, Class<? extends IInterceptor>> interceptors) {
    interceptors.put(1, BaseInterceptor.class);
  }
}

2.4 @Autowired 注解的解析

@Autowired注解的解析依赖于AutowiredProcessor,它的原理和上面类似,都是最终创建一个JavaFile

@AutoService(Processor.class)
@SupportedOptions(KEY_MODULE_NAME)
@SupportedSourceVersion(SourceVersion.RELEASE_7)
@SupportedAnnotationTypes({ANNOTATION_TYPE_AUTOWIRED})
public class AutowiredProcessor extends AbstractProcessor {
    private Filer mFiler;       // File util, write class file into disk.
    private Logger logger;
    private Types types;
    private TypeUtils typeUtils;
    private Elements elements;
    private Map<TypeElement, List<Element>> parentAndChild = new HashMap<>();   // Contain field need autowired and his super class.
    private static final ClassName ARouterClass = ClassName.get("com.alibaba.android.arouter.launcher", "ARouter");
    private static final ClassName AndroidLog = ClassName.get("android.util", "Log");

    @Override
    public synchronized void init(ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);

        mFiler = processingEnv.getFiler();                  // Generate class.
        types = processingEnv.getTypeUtils();            // Get type utils.
        elements = processingEnv.getElementUtils();      // Get class meta.

        typeUtils = new TypeUtils(types, elements);

        logger = new Logger(processingEnv.getMessager());   // Package the log utils.

        logger.info(">>> AutowiredProcessor init. <<<");
    }

    @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;
    }

    /**
     * 开始进行解析。
     * @throws IOException IO 异常。
     * @throws IllegalAccessException 不满足状态的异常。
     */
    private void generateHelper() throws IOException, IllegalAccessException {
        TypeElement type_ISyringe = elements.getTypeElement(ISYRINGE);
        TypeElement type_JsonService = elements.getTypeElement(JSON_SERVICE);
        TypeMirror iProvider = elements.getTypeElement(Consts.IPROVIDER).asType();
        TypeMirror activityTm = elements.getTypeElement(Consts.ACTIVITY).asType();
        TypeMirror fragmentTm = elements.getTypeElement(Consts.FRAGMENT).asType();
        TypeMirror fragmentTmV4 = elements.getTypeElement(Consts.FRAGMENT_V4).asType();

        //1. 函数的形参类型为 Object,形参名为 target。
        ParameterSpec objectParamSpec = ParameterSpec.builder(TypeName.OBJECT, "target").build();

        //2.遍历所有拥有 @Autowired 注解的元素。
        if (MapUtils.isNotEmpty(parentAndChild)) {
            for (Map.Entry<TypeElement, List<Element>> entry : parentAndChild.entrySet()) {
                //2.1 方法名为 inject
                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() + " ... <<<");
                //2.2 类继承于 ISyringe。
                TypeSpec.Builder helper = TypeSpec.classBuilder(fileName)
                        .addJavadoc(WARNING_TIPS)
                        .addSuperinterface(ClassName.get(type_ISyringe))
                        .addModifiers(PUBLIC);

                //2.3 类中包含一个类型为 SerializationService,名称为 serializationService 的成员变量。
                FieldSpec jsonServiceField = FieldSpec.builder(TypeName.get(type_JsonService.asType()), "serializationService", Modifier.PRIVATE).build();
                helper.addField(jsonServiceField);
                
                //2.4 对 Object 类型的形参进行强制转型。
                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));

                //2.5 开始对成员变量遍历进行赋值。
                for (Element element : childs) {
                    Autowired fieldConfig = element.getAnnotation(Autowired.class);
                    String fieldName = element.getSimpleName().toString();
                    //2.5.1 如果是 IProvider 的子类,那么需要获取服务。
                    if (types.isSubtype(element.asType(), iProvider)) { 
                        //没有指定名称,通过类型来获取。
                        if ("".equals(fieldConfig.name())) {

                            // Getter
                            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();
                        }
                    //2.5.2 普通的成员变量。    
                    } else { 
                        String originalValue = "substitute." + fieldName;
                        String statement = "substitute." + fieldName + " = substitute.";
                        boolean isActivity = false;
                        //对 Activity 和 Fragment 进行不同的处理,分别使用 getIntent 和 getArguments 来获取参数。
                        if (types.isSubtype(parent.asType(), activityTm)) {  // Activity, then use getIntent()
                            isActivity = true;
                            statement += "getIntent().";
                        } else if (types.isSubtype(parent.asType(), fragmentTm) || types.isSubtype(parent.asType(), fragmentTmV4)) {   // Fragment, then use getArguments()
                            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.")) {   // Not mortals
                            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()) {  // Primitive wont be check.
                            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());

                //2.6 写入文件。
                JavaFile.builder(packageName, helper.build()).build().writeTo(mFiler);

                logger.info(">>> " + parent.getSimpleName() + " has been processed, " + fileName + " has been generated. <<<");
            }

            logger.info(">>> Autowired processor stop. <<<");
        }
    }

    /**
     * 根据成员变量的类型进行区分。
     * @param originalValue
     * @param statement
     * @param type
     * @param isActivity
     * @return
     */
    private String buildStatement(String originalValue, String statement, int type, boolean isActivity) {
        if (type == TypeKind.BOOLEAN.ordinal()) {
            statement += (isActivity ? ("getBooleanExtra($S, " + originalValue + ")") : ("getBoolean($S)"));
        } else if (type == TypeKind.BYTE.ordinal()) {
            statement += (isActivity ? ("getByteExtra($S, " + originalValue + "") : ("getByte($S)"));
        } else if (type == TypeKind.SHORT.ordinal()) {
            statement += (isActivity ? ("getShortExtra($S, " + originalValue + ")") : ("getShort($S)"));
        } else if (type == TypeKind.INT.ordinal()) {
            statement += (isActivity ? ("getIntExtra($S, " + originalValue + ")") : ("getInt($S)"));
        } else if (type == TypeKind.LONG.ordinal()) {
            statement += (isActivity ? ("getLongExtra($S, " + originalValue + ")") : ("getLong($S)"));
        }else if(type == TypeKind.CHAR.ordinal()){
            statement += (isActivity ? ("getCharExtra($S, " + originalValue + ")") : ("getChar($S)"));
        } else if (type == TypeKind.FLOAT.ordinal()) {
            statement += (isActivity ? ("getFloatExtra($S, " + originalValue + ")") : ("getFloat($S)"));
        } else if (type == TypeKind.DOUBLE.ordinal()) {
            statement += (isActivity ? ("getDoubleExtra($S, " + originalValue + ")") : ("getDouble($S)"));
        } else if (type == TypeKind.STRING.ordinal()) {
            statement += (isActivity ? ("getStringExtra($S)") : ("getString($S)"));
        } else if (type == TypeKind.PARCELABLE.ordinal()) {
            statement += (isActivity ? ("getParcelableExtra($S)") : ("getParcelable($S)"));
        } else if (type == TypeKind.OBJECT.ordinal()) {
            statement = "serializationService.parseObject(substitute." + (isActivity ? "getIntent()." : "getArguments().") + (isActivity ? "getStringExtra($S)" : "getString($S)") + ", new com.alibaba.android.arouter.facade.model.TypeWrapper<$T>(){}.getType())";
        }

        return statement;
    }

    /**
     * 进行分类处理。
     * @param elements
     * @throws IllegalAccessException
     */
    private void categories(Set<? extends Element> elements) throws IllegalAccessException {
        if (CollectionUtils.isNotEmpty(elements)) {
            for (Element element : elements) {
                TypeElement enclosingElement = (TypeElement) element.getEnclosingElement();
                //不允许声明为 private。
                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.");
        }
    }
}

最终创建的文件,其命名规则为 要注入的 Activity/Fragment + $$ARouter$$Autowired,以module-otherInjectActivity为例,最终生成的文件为:

/**
 * DO NOT EDIT THIS FILE!!! IT WAS GENERATED BY AROUTER. */
public class InjectActivity$$ARouter$$Autowired implements ISyringe {
  private SerializationService serializationService;

  @Override
  public void inject(Object target) {
    serializationService = ARouter.getInstance().navigation(SerializationService.class);
    InjectActivity substitute = (InjectActivity)target;
    substitute.age = substitute.getIntent().getIntExtra("inject_age", substitute.age);
    if (null != serializationService) {
      substitute.bean = serializationService.parseObject(substitute.getIntent().getStringExtra("inject_object"), new com.alibaba.android.arouter.facade.model.TypeWrapper<SerialBean>(){}.getType());
    } else {
      Log.e("ARouter::", "You want automatic inject the field 'bean' in class 'InjectActivity' , then you should implement 'SerializationService' to support object auto inject!");
    }
  }
}

当我们调用下面的方法时,就会通过反射创建该类的一个对象,然后调用它的inject方法,依次对各成员变量进行赋值。

ARouter.getInstance().inject(this);

三、总结

以上就是对于Arouter的编译时SDK的分析,这篇文章理解起来可能比较难,因为要求对编译期注解的处理有一定的了解。

通过分析源码,我们学习到了如何在编译期处理注解,并了解到了Arouter分组加载,拦截器以及依赖注入在编译期处理的原理,了解了这些,是我们之后学习Arouter的运行时SDK的基础,也可以借此机会学习它的思想,以后我们有遇到需要在编译期做一些事情的时候,可以拿出来参考。


更多文章,欢迎访问我的 Android 知识梳理系列:

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342