阿里路由框架ARouter 源码解析之Compiler

前段时间,公司项目在做组件化重构,过程中当然会有很多痛点。

组件化最重要的是根据项目和业务进行分模块,至于模块的粒度就看大家自己来把控了!

这里要说的就是模块之间的数据传输问题

组件化之后,各个模块不相互依赖,那么怎么相互跳转和传递数据呢?

答案就是通过隐式Intent 的方式来跳转和传递数据。

以往的显示Intent 跳转,会存在类直接依赖的问题,这样会导致耦合性非常严重;相比而言,隐式Intent则不需要类之间的直接依赖,但是会出现规则集中式管理,扩展性比较差。

所以在调研期间就发现阿里开源了ARouter–路由框架。

ARouter的好处我这里就不多说,大家可以去看官方文档或者去github上看README。

https://github.com/alibaba/ARouter

接下来会分为若干篇blog来分析一下ARouter的源码!

看了ARouter的源码就会发现,它提供了两个SDK,一个是API,一个Compiler。

  • Compiler SDK 是用于编译器生成相关类文件的。
  • API SDK 是用在运行期间路由跳转等作用的。

这里先说说Compiler层SDK。

RouteProcessor 路由路径处理器

InterceptorProcessor 拦截器处理器

AutowireProcessor 自动装配处理器

注解处理器的处理流程

(图片转自网络)

实际上,Compiler SDK 只是处根据扫描到的注解生成相应的映射(java)文件。

最后一步通过固定包名加载映射文件是由API SDK来做的。

以官方demo为例来说:

上图所示就是ARouter在编译期间生成的类文件。

  • 红色标注的是 RouteProcessor 生成的类文件
  • 蓝色标注的是 InterceptorProcessor 生成的类文件
  • 橙色标书的是 AutowiredProcessor 生成的类文件

arouter-compiler的目录结构如下:

  • processor包下面是注解处理器
  • utils包下面是相关工具类

下面分别说说这三种注解处理器:

用过编译时注解的朋友们都知道,注解处理器需要继承AbstractProcessor ,主要涉及的函数有 init(),process() 这两个。

RouteProcessor

类的继承信息:

@AutoService(Processor.class)
@SupportedOptions(KEY_MODULE_NAME)
@SupportedSourceVersion(SourceVersion.RELEASE_7)
@SupportedAnnotationTypes({ANNOTATION_TYPE_ROUTE, ANNOTATION_TYPE_AUTOWIRED})
public class RouteProcessor extends AbstractProcessor {

init

init()

 // 初始化处理器
 @Override
 public synchronized void init(ProcessingEnvironment processingEnv) {
  super.init(processingEnv);

  // 文件管理器
  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.

  // 获取用户配置的[moduleName]
  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 {
   // 如果没有在build.gradle中配置moduleName,则会抛出异常。
   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 = elements.getTypeElement(Consts.IPROVIDER).asType();
  // RouterProcessor 初始化完毕
  logger.info(">>> RouteProcessor init. <<<");
 }
// Consts.java
public static final String KEY_MODULE_NAME = "moduleName";

在使用ARouter注解的时候,按照官方文档是需要在每个module里面的build.gradle中配置如下信息:

javaCompileOptions {
   annotationProcessorOptions {
    arguments = [ moduleName : project.getName() ]
   }
  }

配置这个属性的目的,就是为了在编译期间生成相关module下的文件和存储文件名称。

process()

一般在process()函数中做的操作如下:

  1. 遍历注解的元素
  2. 检验元素是否符合要求(过滤元素)
  3. 获取输出类参数
  4. 生成映射文件(java文件)
  5. 错误处理
 @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... <<<");
    // 调用arseRoute()函数进行处理获取的注解元素集合
    this.parseRoutes(routeElements);

   } catch (Exception e) {
    logger.error(e);
   }
   // 如果有Route元素的注解,并且处理过程中无异常则返回true
   return true;
  }
  // 否则返回false
  return false;
 }

parseRoutes()

这个函数的代码有点长,大家耐心看!

 // Consts.java

 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";

 private static final String FACADE_PACKAGE = "com.alibaba.android.arouter.facade";
 private static final String TEMPLATE_PACKAGE = ".template";

 public static final String IROUTE_GROUP = FACADE_PACKAGE + TEMPLATE_PACKAGE + ".IRouteGroup";

 public static final String IPROVIDER_GROUP = FACADE_PACKAGE + TEMPLATE_PACKAGE + ".IProviderGroup";
private void parseRoutes(Set<? extends Element> routeElements) throws IOException {
  if (CollectionUtils.isNotEmpty(routeElements)) {
   // ...

   rootMap.clear();

   // 获取ACTIVITY, SERVICE, FRAGMENT, FRAGMENT_V4 这四种 类型镜像
   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();

   // ARouter的接口
   TypeElement type_IRouteGroup = elements.getTypeElement(IROUTE_GROUP);
   TypeElement type_IProviderGroup = elements.getTypeElement(IPROVIDER_GROUP);

   //
   // 下面就是遍历获取的注解信息,通过javapoet来生成类文件了 

   ClassName routeMetaCn = ClassName.get(RouteMeta.class);
   ClassName routeTypeCn = ClassName.get(RouteType.class);

   /*
    ParameterizedTypeName用来创建类型对象,例如下面

    ```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))
     )
   );

   /*
    RouteMeta封装了路由相关的信息

    ```Map<String, RouteMeta>```
    */
   ParameterizedTypeName inputMapTypeOfGroup = ParameterizedTypeName.get(
     ClassName.get(Map.class),
     ClassName.get(String.class),
     ClassName.get(RouteMeta.class)
   );

   /*
    创建输入参数
    */

   // 1。 生成的参数:Map<String, Class<? extends IRouteGroup>> routes
   ParameterSpec rootParamSpec = ParameterSpec.builder(inputMapTypeOfRoot, "routes").build(); // 第一个参数表示参数类型,第二个函数表示参数名称

   // 2。 Map<String, RouteMeta> atlas
   ParameterSpec groupParamSpec = ParameterSpec.builder(inputMapTypeOfGroup, "atlas").build();

   // 3。 Map<String, RouteMeta> providers
   ParameterSpec providerParamSpec = ParameterSpec.builder(inputMapTypeOfGroup, "providers").build(); 

   // MethodSpec用来创建方法

   // public static final String METHOD_LOAD_INTO = "loadInto";
   /*
    Build method : 'loadInto'
    */
   MethodSpec.Builder loadIntoMethodOfRootBuilder = MethodSpec.methodBuilder(METHOD_LOAD_INTO)
     .addAnnotation(Override.class) // override
     .addModifiers(PUBLIC) // public
     .addParameter(rootParamSpec); // 参数

   // 创建出来的函数如下
   /**
    * @Override
    * public void loadInto(Map<String, Class<? extends IRouteGroup>> routes) { }
    */ 

   //

   // 接下来的代码就是遍历注解元素,进行分组,进而声称java文件

   for (Element element : routeElements) { // 遍历每个元素

    TypeMirror tm = element.asType();
    Route route = element.getAnnotation(Route.class);
    RouteMeta routeMete = null;

    // 判断类型
    if (types.isSubtype(tm, type_Activity)) { // Activity
     logger.info(">>> Found activity route: " + tm.toString() + " <<<");

     Map<String, Integer> paramsType = new HashMap<>();

     // 遍历查找所有添加 @AutoWired 注解的变量
     for (Element field : element.getEnclosedElements()) {

      // 1. 必须是field
      // 2. 必须有注解AutoWired
      // 3. 必须不是IProvider类型

      if (field.getKind().isField() && field.getAnnotation(Autowired.class) != null && !types.isSubtype(field.asType(), iProvider)) {
       // 满足上述条件后,获取注解
       Autowired paramConfig = field.getAnnotation(Autowired.class);

       // 看过源码就知道,Autowired支持写别名,当指定name属性之后,就会以name为准,否则以field的名字为准。
       // TypeUtils是自定义工具类,用来判断field的数据类型的,转换成int值。

       paramsType.put(StringUtils.isEmpty(paramConfig.name()) ? field.getSimpleName().toString() : paramConfig.name(), typeUtils.typeExchange(field));
      }

     // 构建一条路由信息,将字段注解信息保存进去

     routeMete = new RouteMeta(route, element, RouteType.ACTIVITY, paramsType);
    } 

    // 如果是IProvider类型的注解,则直接创建一条PROVIDER类型的路由信息
    else if (types.isSubtype(tm, iProvider)) {
     routeMete = new RouteMeta(route, element, RouteType.PROVIDER, null);
    }
    // 如果是Service类型的注解,则直接创建一条Service类型的路由信息
    else if (types.isSubtype(tm, type_Service)) {   // Service
     routeMete = new RouteMeta(route, element, RouteType.parse(Service), null);
    }
    // 如果是fragmentTmV4类型的注解,则直接创建一条Fragment类型的路由信息
    else if (types.isSubtype(tm, fragmentTm) || types.isSubtype(tm, fragmentTmV4)) {
     routeMete = new RouteMeta(route, element, RouteType.parse(FRAGMENT), null);
    }

    // 将路由信息进行分组 (每个路由信息对象中都保存着它所属的组别信息,在调用categories()函数之前所有的组别信息都是默认值"" )
    categories(routeMete);

   }

   // 第一次遍历之前,已经创建了ROOT类的loadInto函数
   // 下面开始创建Provider类的loadInto函数
   MethodSpec.Builder loadIntoMethodOfProviderBuilder = MethodSpec.methodBuilder(METHOD_LOAD_INTO)
     .addAnnotation(Override.class)
     .addModifiers(PUBLIC)
     .addParameter(providerParamSpec);

   // 创建出来的函数如下
   /**
    * @Override
    * public void loadInto(Map<String, RouteMeta> providers) { }
    */   

   // 接着,遍历所有在 categories(routeMete); 得到的所有组别

   for (Map.Entry<String, Set<RouteMeta>> entry : groupMap.entrySet()) {
    String groupName = entry.getKey();

    // 创建分组类的函数 -- loadInto(Map<String, RouteMeta> atlas)
    MethodSpec.Builder loadIntoMethodOfGroupBuilder = MethodSpec.methodBuilder(METHOD_LOAD_INTO)
      .addAnnotation(Override.class)
      .addModifiers(PUBLIC)
      .addParameter(groupParamSpec);

    // 往组别函数loadInto中添加数据
    Set<RouteMeta> groupData = entry.getValue();

    // PROVIDERL 类型的数据需要特殊处理

    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)) { 

   // 这种情况下,在loadInfo()函数里面添加的语句类似于:
   // singleService直接实现IProvider接口

   /**
    * @Route(path = "/service/single")
    * public class SingleService implements IProvider
    *
    * providers.put("com.alibaba.android.arouter.demo.testservice.SingleService", RouteMeta.build(RouteType.PROVIDER, SingleService.class, "/service/single", "service", null, -1, -2147483648));
    */         

         loadIntoMethodOfProviderBuilder.addStatement(
           "providers.put($S, $T.build($T." + routeMeta.getType() + ", $T.class, $S, $S, null, " + routeMeta.getPriority() + ", " + routeMeta.getExtra() + "))",
           (routeMeta.getRawType()).toString(),
           routeMetaCn,
           routeTypeCn,
           ClassName.get((TypeElement) routeMeta.getRawType()),
           routeMeta.getPath(),
           routeMeta.getGroup());

        } else if (types.isSubtype(tm, iProvider)) {
         // 如果是接口继承的IProvider

   // 这种情况下,在loadInfo()函数里面添加的语句类似于:
   // singleService直接实现IProvider接口

   /**
    * @Route(path = "/service/hello")
    * public class HelloServiceImpl implements HelloService
    * public interface HelloService extends IProvider
    * //
    * providers.put("com.alibaba.android.arouter.demo.testservice.HelloService", RouteMeta.build(RouteType.PROVIDER, HelloServiceImpl.class, "/service/hello", "service", null, -1, -2147483648));
    */            

         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.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("); ");
      }
     }
     // // 形式如: put("pac", 9); put("obj", 10);
     String mapBody = mapBodyBuilder.toString();

     // 往loadInto函数里面添加一个语句
     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, // RouteMeta
       routeTypeCn, // RouteType
       ClassName.get((TypeElement) routeMeta.getRawType()), // 注解原生类的名称
       routeMeta.getPath().toLowerCase(), // 完整路径
       routeMeta.getGroup().toLowerCase()); // 组名
    }

    // 添加的语句如下:
    // atlas.put("/test/activity1", RouteMeta.build(RouteType.ACTIVITY, Test1Activity.class, "/test/activity1", "test", new java.util.HashMap<String, Integer>(){{put("pac", 9); put("obj", 10); put("name", 8); put("boy", 0); put("age", 3); put("url", 8); }}, -1, -2147483648));

    // 生成组类别java文件
    // public static final String NAME_OF_GROUP = PROJECT + SEPARATOR + "Group" + SEPARATOR;
    // public static final String SEPARATOR = "$$";
    // public static final String PROJECT = "ARouter";
    String groupFileName = NAME_OF_GROUP + groupName;

    JavaFile.builder(PACKAGE_OF_GENERATE_FILE, // package 名称 --"com.alibaba.android.arouter.routes"
      TypeSpec.classBuilder(groupFileName) //java类名
        .addJavadoc(WARNING_TIPS) // doc
        .addSuperinterface(ClassName.get(type_IRouteGroup)) // 添加继承的接口
        .addModifiers(PUBLIC) // 作用域为public
        .addMethod(loadIntoMethodOfGroupBuilder.build()) // 添加函数(包括了函数里面的代码块)
        .build()
    ).build().writeTo(mFiler);

    // 将组名和组文件名放到map中,方便按需加载
    rootMap.put(groupName, groupFileName);
   }

  // .................................................................... //

   // 经过了上面的for循环,生成了如 ARouter$$Group$$service.java 和ARouter$$Group$$test.java 文件,它们所在的包是 com.alibaba.android.arouter.routes。

   if (MapUtils.isNotEmpty(rootMap)) {
    // 遍历这些group,进而生成Root类文件
    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()));

     // 每一个statement如: routes.put("test", ARouter$$Group$$test.class);
    }
   }

   // 生成provider类文件

   // provider文件名为:ARouter$$Providers$$xxx
   String providerMapFileName = NAME_OF_PROVIDER + SEPARATOR + moduleName;
   JavaFile.builder(PACKAGE_OF_GENERATE_FILE,
     TypeSpec.classBuilder(providerMapFileName)
       .addJavadoc(WARNING_TIPS)
       .addSuperinterface(ClassName.get(type_IProviderGroup))
       .addModifiers(PUBLIC)
       .addMethod(loadIntoMethodOfProviderBuilder.build())
       .build()
   ).build().writeTo(mFiler);

   // 生成root文件
   // ARouter$$Root$$xxx
   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);

  }
 }

categories()

下面来看一下怎么讲路由进行分组的

private void categories(RouteMeta routeMete) {
  // 首先去验证这条路由信息
  if (routeVerify(routeMete)) {
   // 尝试从groupMap中通过group名称获取路由信息
   Set<RouteMeta> routeMetas = groupMap.get(routeMete.getGroup());
   if (CollectionUtils.isEmpty(routeMetas)) { // 如果map中没有相关记录,则表示这个组别还未添加到map中
    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;
      }
     }
    });
    // 添加该组别到map中
    routeMetaSet.add(routeMete);
    groupMap.put(routeMete.getGroup(), routeMetaSet);
   } else { // 如果存在该组别则添加到这一组中
    routeMetas.add(routeMete);
   }
  } else {
   // 验证路由信息不正确是会在编译期间输出错误日志
   logger.warning(">>> Route meta verify error, group is " + routeMete.getGroup() + " <<<");
  }
 }

routeVerify()

// 验证路由信息的正确性
private boolean routeVerify(RouteMeta meta) {
  String path = meta.getPath();
  // 判断路径是否为空或者是否以“/”开头
  if (StringUtils.isEmpty(path) || !path.startsWith("/")) { // The path must be start with '/' and not empty!
   return false;
  }
  // 没有分组时,group为""
  if (StringUtils.isEmpty(meta.getGroup())) { // Use default group(the first word in path)
   try {
    // 截取字符串获取group
    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;
 }

通过上面的分析可以得到以下几点:

配置Route注解时,路径不允许为空且必须以“/”开头

RouteProcessor注解处理器生成的文件由三种:

1. ARouter$$Group$$xxx (可能有多个)
2. ARouter$$Providers$$xxx (只有一个)
3. ARouter$$Root$$xxx (只有一个)

InterceptorProcessor

@AutoService(Processor.class)
@SupportedOptions(KEY_MODULE_NAME)
@SupportedSourceVersion(SourceVersion.RELEASE_7)
@SupportedAnnotationTypes(ANNOTATION_TYPE_INTECEPTOR)
public class InterceptorProcessor extends AbstractProcessor

init()

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

  // ... 省略代码与RouteProcressor基本一样

  iInterceptor = elementUtil.getTypeElement(Consts.IINTERCEPTOR).asType();
 }

process()

 @Override
 public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
  if (CollectionUtils.isNotEmpty(annotations)) {
   // 获取Interceptor注解的集合
   Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(Interceptor.class);
   try {
    // 处理注解信息
    parseInterceptors(elements);
   } catch (Exception e) {
    logger.error(e);
   }
   return true;
  }

  return false;
 }

parseInterceptors()

private Map<Integer, Element> interceptors = new TreeMap<>();
private void parseInterceptors(Set<? extends Element> elements) throws IOException {
  if (CollectionUtils.isNotEmpty(elements)) {
   // 遍历注解元素
   for (Element element : elements) {
    if (verify(element)) { // 做验证

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

   // Interface of ARouter.
   TypeElement type_ITollgate = elementUtil.getTypeElement(IINTERCEPTOR);
   TypeElement type_ITollgateGroup = elementUtil.getTypeElement(IINTERCEPTOR_GROUP);

   /**
    * 创建类型对象
    *
    * ```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))
     )
   );

   // 构建输入参数
   ParameterSpec tollgateParamSpec = ParameterSpec.builder(inputMapTypeOfTollgate, "interceptors").build();

   // 创建函数 : 'loadInto'
   MethodSpec.Builder loadIntoMethodOfTollgateBuilder = MethodSpec.methodBuilder(METHOD_LOAD_INTO)
     .addAnnotation(Override.class)
     .addModifiers(PUBLIC)
     .addParameter(tollgateParamSpec);

   // 遍历拦截器结合,往loadInto函数中添加语句
   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()));

    // 语句类似于
    // interceptors.put(1, Test1Interceptor.class);
    }
   }

   // 写入文件
   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. <<<");
  }
 }

verify()

// 验证注解元素是否合格
private boolean verify(Element element) {
  Interceptor interceptor = element.getAnnotation(Interceptor.class);
  return null != interceptor && ((TypeElement)element).getInterfaces().contains(iInterceptor);
 }

通过上面的分析可以得到以下几点:

不能设置相同优先级的拦截器,否则会抛出异常

InterceptorProcessor生成的类文件格式为:ARouter$$Interceptors$$xxx

AutowiredProcessor

@AutoService(Processor.class)
@SupportedOptions(KEY_MODULE_NAME)
@SupportedSourceVersion(SourceVersion.RELEASE_7)
@SupportedAnnotationTypes({ANNOTATION_TYPE_AUTOWIRED})
public class AutowiredProcessor extends AbstractProcessor

init()

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

process()

 // process函数主要关注两点 categories() 和 generateHelper()
 @Override
 public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
  if (CollectionUtils.isNotEmpty(set)) {
   try {
    logger.info(">>> Found autowired field, start... <<<");
    // 1. 分组
    categories(roundEnvironment.getElementsAnnotatedWith(Autowired.class));
    // 2.
    generateHelper();

   } catch (Exception e) {
    logger.error(e);
   }
   return true;
  }

  return false;
 }

categories

private Map<TypeElement, List<Element>> parentAndChild = new HashMap<>();
// 将注解元素分组
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 autowired fields CAN NOT BE 'private'!!! please check field ["
       + element.getSimpleName() + "] in class [" + enclosingElement.getQualifiedName() + "]");
    }
    // 判断集合中是否存在集合中
    if (parentAndChild.containsKey(enclosingElement)) { // Has categries
     parentAndChild.get(enclosingElement).add(element);
    } else {
     List<Element> childs = new ArrayList<>();
     childs.add(element);
     parentAndChild.put(enclosingElement, childs);
    }
   }

   logger.info("categories finished.");
  }
 }

generateHelper

 //
 private void generateHelper() throws IOException, IllegalAccessException {
  // ISyringe
  TypeElement type_ISyringe = elements.getTypeElement(ISYRINGE);
  // SerializationService
  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();

  // 构建输入参数
  ParameterSpec objectParamSpec = ParameterSpec.builder(TypeName.OBJECT, "target").build();
  // 遍历分组的集合
  if (MapUtils.isNotEmpty(parentAndChild)) {
   for (Map.Entry<TypeElement, List<Element>> entry : parentAndChild.entrySet()) {
    // 构建函数 : '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("."));

    // 文件名称例如:Test1Activity$$ARouter$$Autowired
    String fileName = parent.getSimpleName() + NAME_OF_AUTOWIRED;

    //
    TypeSpec.Builder helper = TypeSpec.classBuilder(fileName)
      .addJavadoc(WARNING_TIPS)
      .addSuperinterface(ClassName.get(type_ISyringe))
      .addModifiers(PUBLIC);
    // 构建SerializationService 字段
    FieldSpec jsonServiceField = FieldSpec.builder(TypeName.get(type_JsonService.asType()), "serializationService", Modifier.PRIVATE).build();
    // 添加字段
    helper.addField(jsonServiceField);
    // inject函数中添加语句
    // serializationService = ARouter.getInstance().navigation(SerializationService.class);

    injectMethodBuilder.addStatement("serializationService = $T.getInstance().navigation($T.class);", ARouterClass, ClassName.get(type_JsonService));

    // 转换对象
    // 比如:Test1Activity substitute = (Test1Activity)target;
    injectMethodBuilder.addStatement("$T substitute = ($T)target", ClassName.get(parent), ClassName.get(parent));

    // 遍历注解变量
    for (Element element : childs) {
     Autowired fieldConfig = element.getAnnotation(Autowired.class);
     String fieldName = element.getSimpleName().toString();

     // 判断是否是IProvider类型
     if (types.isSubtype(element.asType(), iProvider)) {
      // 如果name为空,则通过Type方式
      if ("".equals(fieldConfig.name())) { 

       injectMethodBuilder.addStatement(
         "substitute." + fieldName + " = $T.getInstance().navigation($T.class)",
         ARouterClass,
         ClassName.get(element.asType())
       );
      } else { // 如果name不为空,则通过name方式

       injectMethodBuilder.addStatement(
         "substitute." + fieldName + " = ($T)$T.getInstance().build($S).navigation();",
         ClassName.get(element.asType()),
         ARouterClass,
         fieldConfig.name()
       );
      }

      // 是否是必须传值字段,这里加入了if判断
      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 { // It's normal intent value
      String statment = "substitute." + fieldName + " = substitute.";
      boolean isActivity = false;
      // Activity类型时,通过 getIntent() 方式

      if (types.isSubtype(parent.asType(), activityTm)) {
       isActivity = true;
       statment += "getIntent().";
      }
      // Fragment类型, 使用 getArguments()
       else if (types.isSubtype(parent.asType(), fragmentTm) || types.isSubtype(parent.asType(), fragmentTmV4)) {
       statment += "getArguments().";
      }
      // 非Activity或者非Fragment,则抛出异常
      else {
       throw new IllegalAccessException("The field [" + fieldName + "] need autowired from intent, its parent must be activity or fragment!");
      }

      statment = buildStatement(statment, typeUtils.typeExchange(element), isActivity);

      // 针对SerializationService添加判空操作
      if (statment.startsWith("serializationService.")) { // Not mortals
       injectMethodBuilder.beginControlFlow("if (null != serializationService)");
       injectMethodBuilder.addStatement(
         "substitute." + fieldName + " = " + statment,
         (StringUtils.isEmpty(fieldConfig.name()) ? fieldName : fieldConfig.name()),
         ClassName.get(element.asType())
       );
       injectMethodBuilder.nextControlFlow("else");
       injectMethodBuilder.addStatement(
         "$T.e(\"" + Consts.TAG + "\", \"You want automatic inject the field '" + fieldName + "' in class '$T' , then you should implement 'SerializationService' to support object auto inject!\")", AndroidLog, ClassName.get(parent));
       injectMethodBuilder.endControlFlow();
      } else {
       injectMethodBuilder.addStatement(statment, StringUtils.isEmpty(fieldConfig.name()) ? fieldName : fieldConfig.name());
      }

      // Validator
      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();
      }
     }
    }
    // 往类中添加inject() 函数
    helper.addMethod(injectMethodBuilder.build());

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

   }

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

AutowiredProcessor生成的java文件举例如下:

public class Test1Activity$$ARouter$$Autowired implements ISyringe {
 private SerializationService serializationService;

 @Override
 public void inject(Object target) {
 serializationService = ARouter.getInstance().navigation(SerializationService.class);;
 Test1Activity substitute = (Test1Activity)target;
 substitute.name = substitute.getIntent().getStringExtra("name");
 substitute.age = substitute.getIntent().getIntExtra("age", 0);
 substitute.girl = substitute.getIntent().getBooleanExtra("boy", false);
 substitute.pac = substitute.getIntent().getParcelableExtra("pac");
 if (null != serializationService) {
  substitute.obj = serializationService.json2Object(substitute.getIntent().getStringExtra("obj"), TestObj.class);
 } else {
  Log.e("ARouter::", "You want automatic inject the field 'obj' in class 'Test1Activity' , then you should implement 'SerializationService' to support object auto inject!");
 }
 substitute.url = substitute.getIntent().getStringExtra("url");
 substitute.helloService = ARouter.getInstance().navigation(HelloService.class);
 }
}

总结

至此,ARouter之Compiler SDK中的三种注解处理器都分析完毕!

接下来的文章开始分析API SDK的源码!以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android ARouter路由框架解析

    一.ARouter介绍及主要应用场景: 1.介绍: 是ARouter是阿里巴巴开源的Android平台中对页面.服务提供路由功能的中间件,提倡的是简单且够用. 2.原生的路由方案存在的问题 首先谈一谈原生的路由方案存在的问题以及为什么需要路由框架.我们所使用的原生路由方案一般是通过显式intent和隐式intent两种方式实现的,而在显式intent的情况下,因为会存在直接的类依赖的问题,导致耦合非常严重:而在隐式intent情况下,则会出现规则集中式管理,导致协作变得非常困难.而且一般而言配置

  • Android路由框架ARouter分析

    一.路由方案 原生的路由方案缺点: 显式:直接的类依赖,耦合严重 隐式:规则集中式管理,协作困难 Manifest扩展性较差 跳转过程无法控制 失败无法降级 ARouter的优势: 使用注解,实现了映射关系自动注册 与 分布式路由管理 编译期间处理注解,并生成映射文件,没有使用反射,不影响运行时性能 映射关系按组分类.多级管理,按需初始化 灵活的降级策略,每次跳转都会回调跳转结果,避免StartActivity()一旦失败将会抛出运营级异常 自定义拦截器,自定义拦截顺序,可以对路由进行拦截,比如

  • [Alibaba-ARouter]浅谈简单好用的Android页面路由框架

    开发一款App,总会遇到各种各样的需求和业务,这时候选择一个简单好用的轮子,就可以事半功倍 前言 Intent intent = new Intent(mContext, XxxActivity.class); intent.putExtra("key","value"); startActivity(intent); Intent intent = new Intent(mContext, XxxActivity.class); intent.putExtra(&

  • 浅谈android组件化之ARouter简单使用

    ARouter是阿里巴巴开源出来的一款android路由框架,github地址为 : https://github.com/alibaba/ARouter 至于ARouter的诸多好处我就不介绍了,这里主要讲解在项目组件化下,ARouter的一些简单使用 先贴上工程目录: 工程一共分为4个模块,基础组件app.基础服务(包涵路由服务)basecommonlibrary模块.业务模块libraryone.业务模块librarytwo; 在4个模块的gradle文件当中加入如下代码: android

  • 阿里路由框架ARouter 源码解析之Compiler

    前段时间,公司项目在做组件化重构,过程中当然会有很多痛点. 组件化最重要的是根据项目和业务进行分模块,至于模块的粒度就看大家自己来把控了! 这里要说的就是模块之间的数据传输问题 组件化之后,各个模块不相互依赖,那么怎么相互跳转和传递数据呢? 答案就是通过隐式Intent 的方式来跳转和传递数据. 以往的显示Intent 跳转,会存在类直接依赖的问题,这样会导致耦合性非常严重:相比而言,隐式Intent则不需要类之间的直接依赖,但是会出现规则集中式管理,扩展性比较差. 所以在调研期间就发现阿里开源

  • springboot默认日志框架选择源码解析(推荐)

    背景: 今天新生成一个springboot项目,然而启动日志,还有mybatis的详细日志无法打印出来,自写程序中打印的日志可以输出:网上找了很多资料,都没法解决问题:于是决定跟一下源码,弄清springboot日志相关的逻辑. 环境配置:macbook: intellij idea community edition 2020.03 : gradle 6.8.3 jdk1.8 : gradle引用包如下: dependencies { compile "com.alibaba:fastjson

  • Laravel框架源码解析之入口文件原理分析

    本文实例讲述了Laravel框架源码解析之入口文件原理.分享给大家供大家参考,具体如下: 前言 提升能力的方法并非使用更多工具,而是解刨自己所使用的工具.今天我们从Laravel启动的第一步开始讲起. 入口文件 laravel是单入口框架,所有请求必将经过index.php define('LARAVEL_START', microtime(true)); // 获取启动时间 使用composer是现代PHP的标志 require __DIR__.'/../vendor/autoload.php

  • Laravel源码解析之路由的使用和示例详解

    前言 我的解析文章并非深层次多领域的解析攻略.但是参考着开发文档看此类文章会让你在日常开发中更上一层楼. 废话不多说,我们开始本章的讲解. 入口 Laravel启动后,会先加载服务提供者.中间件等组件,在查找路由之前因为我们使用的是门面,所以先要查到Route的实体类. 注册 第一步当然还是通过服务提供者,因为这是laravel启动的关键,在 RouteServiceProvider 内加载路由文件. protected function mapApiRoutes() { Route::pref

  • Laravel框架源码解析之模型Model原理与用法解析

    本文实例讲述了Laravel框架源码解析之模型Model原理与用法.分享给大家供大家参考,具体如下: 前言 提前预祝猿人们国庆快乐,吃好.喝好.玩好,我会在电视上看着你们. 根据单一责任开发原则来讲,在laravel的开发过程中每个表都应建立一个model对外服务和调用.类似于这样 namespace App\Models; use Illuminate\Database\Eloquent\Model; class User extends Model { protected $table =

  • Laravel框架源码解析之反射的使用详解

    本文实例讲述了Laravel框架源码解析之反射的使用.分享给大家供大家参考,具体如下: 前言 PHP的反射类与实例化对象作用相反,实例化是调用封装类中的方法.成员,而反射类则是拆封类中的所有方法.成员变量,并包括私有方法等.就如"解刨"一样,我们可以调用任何关键字修饰的方法.成员.当然在正常业务中是建议不使用,比较反射类已经摒弃了封装的概念. 本章讲解反射类的使用及Laravel对反射的使用. 反射 反射类是PHP内部类,无需加载即可使用,你可以通过实例化 ReflectionClas

  • JetCache 缓存框架的使用及源码解析(推荐)

    目录 一.简介 为什么使用缓存? 使用场景 使用规范 二.如何使用 引入maven依赖 添加配置 配置说明 注解说明 @EnableCreateCacheAnnotation @EnableMethodCache @CacheInvalidate @CacheUpdate @CacheRefresh @CachePenetrationProtect @CreateCache 三.源码解析 项目的各个子模块 常用注解与变量 缓存API Cache接口 AbstractCache抽象类 Abstra

  • Android音视频开发Media FrameWork框架源码解析

    目录 一.Media FrameWork背景 二.Media Framework“路线图” 2.1 代理端 2.2 服务端 2.2.1 Source 2.2.2 Decoder 2.2.3 Renderer 2.2.4 Foundation 2.3 OMX端 2.4 Kernel端 三.media播放的流程 四.Media FrameWork源码分析 一.Media FrameWork背景 Media Framework (媒体函数库):此函数库让Android 可以播放与录制许多常见的音频与视

  • Android路由框架ARouter的使用示例

    目录 一.添加依赖和初始化框架 1.添加依赖 1.1.java版本的依赖 1.2.kotlin版本的依赖 2.初始化SDK 二.ARouter的简单使用 1.界面跳转 1.1.Activity界面跳转 1.2.获取fragment实例 1.3.注意事项 2.携带基本参数的界面跳转 3.携带对象的界面跳转 3.1.携带序列化对象的界面跳转 3.2.携带无序列化对象的界面跳转 3.3.携带集合和数组的界面跳转 4.界面跳转回调 5.未用到的知识点 一.添加依赖和初始化框架 1.添加依赖 在需要使用A

随机推荐