美文网首页
ARouter注解处理器分析-AutowiredProcesso

ARouter注解处理器分析-AutowiredProcesso

作者: dashingqi | 来源:发表于2020-07-16 18:48 被阅读0次
Android_Banner.jpg

简介

  • AutowiredProcessor注解处理器是用来处理ARouter中Autowired注解,在process方法中编写处理逻辑
  • 通常我们使用@Autowired注解来作用于目标类中的代接受数据的变量
  • 我们看下生成的类文件,如图所示
WX20200713-180404@2x.png

源码分析

看下AutowiredProcessor
/处理@Autowired注解处理器
@SupportedAnnotationTypes({ANNOTATION_TYPE_AUTOWIRED})
//继承BaseProcessor
public class AutowiredProcessor extends BaseProcessor {}
AutowiredProcessor # process()
 @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;
    }
分析1:AutowiredProcessor # categories()
    private void categories(Set<? extends Element> elements) throws IllegalAccessException {
        if (CollectionUtils.isNotEmpty(elements)) {
            // 使用@Autowired注解的类元素集合 elements
            for (Element element : elements) {
                //转换成类对应的Element ----->  TypeElement
                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() + "]");
                }

                // 当前类对应的typeElement为key 是否存存在于缓存中
                if (parentAndChild.containsKey(enclosingElement)) { // Has categries
                    //如果存在 就将当前的element(类中@Autowired注解作用的成员变量)存在集合中
                    parentAndChild.get(enclosingElement).add(element);
                } else {
                    //不存在,创建一个集合 存储这个element
                    List<Element> childs = new ArrayList<>();
                    childs.add(element);
                    //同时存储在parentAndChild (Map中)
                    parentAndChild.put(enclosingElement, childs);
                }
            }

            logger.info("categories finished.");
        }
    }
  • 总结
    • categories()方法是用来进行分类的,set集合中装载这被@Autowired注解修饰的成员,这些成员有分别属于的类,
    • 在此方法中 以Map集中来存储 类与类中被@Autowired注解修饰的成员变量的映射关系,其中被@Autowired注解修饰成员存储在List集合中
AutowiredProcessor # generateHelper()
 private void generateHelper() throws IOException, IllegalAccessException {
        TypeElement type_ISyringe = elementUtils.getTypeElement(ISYRINGE);
        TypeElement type_JsonService = elementUtils.getTypeElement(JSON_SERVICE);
        TypeMirror iProvider = elementUtils.getTypeElement(Consts.IPROVIDER).asType();
        TypeMirror activityTm = elementUtils.getTypeElement(Consts.ACTIVITY).asType();
        TypeMirror fragmentTm = elementUtils.getTypeElement(Consts.FRAGMENT).asType();
        TypeMirror fragmentTmV4 = elementUtils.getTypeElement(Consts.FRAGMENT_V4).asType();

        // Build input param name.
        //构建方法的参数名称
        ParameterSpec objectParamSpec = ParameterSpec.builder(TypeName.OBJECT, "target").build();

        if (MapUtils.isNotEmpty(parentAndChild)) {
            for (Map.Entry<TypeElement, List<Element>> entry : parentAndChild.entrySet()) {
                // Build method : 'inject'
                //构建inject方法
                /**
                 * public void inject(Object target){}
                 */
                MethodSpec.Builder injectMethodBuilder = MethodSpec.methodBuilder(METHOD_INJECT)
                        .addAnnotation(Override.class)
                        .addModifiers(PUBLIC)
                        .addParameter(objectParamSpec);

                //类
                TypeElement parent = entry.getKey();
                // 类中被@Autowired注解作用的成员集合
                List<Element> childs = entry.getValue();

                //类名
                String qualifiedName = parent.getQualifiedName().toString();
                String packageName = qualifiedName.substring(0, qualifiedName.lastIndexOf("."));
                //构建生成文件的类名 类名$$ARouter$$Autowired
                String fileName = parent.getSimpleName() + NAME_OF_AUTOWIRED;

                logger.info(">>> Start process " + childs.size() + " field in " + parent.getSimpleName() + " ... <<<");

                //构建类
                /**
                 * public class className$$ARouter$$Autowired implements ISyringe{}
                 */
                TypeSpec.Builder helper = TypeSpec.classBuilder(fileName)
                        .addJavadoc(WARNING_TIPS)
                        .addSuperinterface(ClassName.get(type_ISyringe))
                        .addModifiers(PUBLIC);

                /**
                 * 序列化
                 */
                FieldSpec jsonServiceField = FieldSpec.builder(TypeName.get(type_JsonService.asType()), "serializationService", Modifier.PRIVATE).build();
                helper.addField(jsonServiceField);

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

                // Generate method body, start inject.
                /**
                 * 遍历集合,拿到该类中被@Autowired注解修饰的成员 element
                 */
                for (Element element : childs) {
                    Autowired fieldConfig = element.getAnnotation(Autowired.class);
                    String fieldName = element.getSimpleName().toString();
                    if (types.isSubtype(element.asType(), iProvider)) {// It's provider
                        //当成员中存在是Provider类型的 通过IoC ByType的方式 获取到它的实例
                        if ("".equals(fieldConfig.name())) {    // User has not set service path, then use byType.

                            // Getter
                            injectMethodBuilder.addStatement(
                                    "substitute." + fieldName + " = $T.getInstance().navigation($T.class)",
                                    ARouterClass,
                                    ClassName.get(element.asType())
                            );
                        } else {    // use byName
                            // Getter
                            injectMethodBuilder.addStatement(
                                    "substitute." + fieldName + " = ($T)$T.getInstance().build($S).navigation()",
                                    ClassName.get(element.asType()),
                                    ARouterClass,
                                    fieldConfig.name()
                            );
                        }

                        // Validater
                        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 originalValue = "substitute." + fieldName;
                        String statement = "substitute." + fieldName + " = " + buildCastCode(element) + "substitute.";
                        boolean isActivity = false;
                        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!");
                        }
                        // 为成员赋值,通过从Intent中拿到对应的值,直接赋值给成员变量
                        statement = buildStatement(originalValue, statement, typeUtils.typeExchange(element), isActivity);
                        // 从json中解析出对应的对象
                        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())
                            );
                            //当没有找到实现SerializationService接口的的实现类的时候,会打印一个错误的信息log
                            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());
                        }

                        // 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();
                        }
                    }
                }
                /**
                 * 给类文件加入方法
                 */
                helper.addMethod(injectMethodBuilder.build());

                // Generate autowire helper
                //生成对应的文件类 (className$$ARouter$$Autowired)
                JavaFile.builder(packageName, helper.build()).build().writeTo(mFiler);

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

            logger.info(">>> Autowired processor stop. <<<");
        }
    }
  • 总结
    • generateHelper()方法中,用来生成文件类的,包括类,方法以及方法的参数和方法体的逻辑
    • 生成的文件类与parentAndChild的map集合形成对应,类中的方法体主要用来进行赋值的操作,包括基本数据类型的变量复制以及对象的赋值
    • 在方法体中是通过类的实例.变量名的形式 进行赋值的,所以被@Autowired注解修饰的变量不能是private。

相关文章

网友评论

      本文标题:ARouter注解处理器分析-AutowiredProcesso

      本文链接:https://www.haomeiwen.com/subject/eevacktx.html