十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
前段时间,公司项目在做组件化重构,过程中当然会有很多痛点。
成都创新互联坚持“要么做到,要么别承诺”的工作理念,服务领域包括:做网站、网站建设、企业官网、英文网站、手机端网站、网站推广等服务,满足客户于互联网时代的稷山网站设计、移动媒体设计的需求,帮助企业找到有效的互联网解决方案。努力成为您成熟可靠的网络建设合作伙伴!
组件化最重要的是根据项目和业务进行分模块,至于模块的粒度就看大家自己来把控了!
这里要说的就是模块之间的数据传输问题
组件化之后,各个模块不相互依赖,那么怎么相互跳转和传递数据呢?
答案就是通过隐式Intent 的方式来跳转和传递数据。
以往的显示Intent 跳转,会存在类直接依赖的问题,这样会导致耦合性非常严重;相比而言,隐式Intent则不需要类之间的直接依赖,但是会出现规则集中式管理,扩展性比较差。
所以在调研期间就发现阿里开源了ARouter–路由框架。
ARouter的好处我这里就不多说,大家可以去看官方文档或者去github上看README。
【https://github.com/alibaba/ARouter】
接下来会分为若干篇blog来分析一下ARouter的源码!
看了ARouter的源码就会发现,它提供了两个SDK,一个是API,一个Compiler。
这里先说说Compiler层SDK。
RouteProcessor 路由路径处理器
InterceptorProcessor 拦截器处理器
AutowireProcessor 自动装配处理器
注解处理器的处理流程
(图片转自网络)
实际上,Compiler SDK 只是处根据扫描到的注解生成相应的映射(java)文件。
最后一步通过固定包名加载映射文件是由API SDK来做的。
以官方demo为例来说:
上图所示就是ARouter在编译期间生成的类文件。
arouter-compiler的目录结构如下:
下面分别说说这三种注解处理器:
用过编译时注解的朋友们都知道,注解处理器需要继承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] Mapoptions = 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()函数中做的操作如下:
@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>``` */ 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 ``` */ ParameterizedTypeName inputMapTypeOfGroup = ParameterizedTypeName.get( ClassName.get(Map.class), ClassName.get(String.class), ClassName.get(RouteMeta.class) ); /* 创建输入参数 */ // 1。 生成的参数:Map > routes ParameterSpec rootParamSpec = ParameterSpec.builder(inputMapTypeOfRoot, "routes").build(); // 第一个参数表示参数类型,第二个函数表示参数名称 // 2。 Map atlas ParameterSpec groupParamSpec = ParameterSpec.builder(inputMapTypeOfGroup, "atlas").build(); // 3。 Map 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 > 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 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 providers) { } */ // 接着,遍历所有在 categories(routeMete); 得到的所有组别 for (Map.Entry > entry : groupMap.entrySet()) { String groupName = entry.getKey(); // 创建分组类的函数 -- loadInto(Map atlas) MethodSpec.Builder loadIntoMethodOfGroupBuilder = MethodSpec.methodBuilder(METHOD_LOAD_INTO) .addAnnotation(Override.class) .addModifiers(PUBLIC) .addParameter(groupParamSpec); // 往组别函数loadInto中添加数据 Set 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 paramsType = routeMeta.getParamsType(); if (MapUtils.isNotEmpty(paramsType)) { for (Map.Entry 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 (){{" + 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 (){{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 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名称获取路由信息 SetrouteMetas = groupMap.get(routeMete.getGroup()); if (CollectionUtils.isEmpty(routeMetas)) { // 如果map中没有相关记录,则表示这个组别还未添加到map中 Set routeMetaSet = new TreeSet<>(new Comparator () { @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 Mapinterceptors = 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>``` */ 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 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> 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 { Listchilds = 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> entry : parentAndChild.entrySet()) { // 构建函数 : 'inject' MethodSpec.Builder injectMethodBuilder = MethodSpec.methodBuilder(METHOD_INJECT) .addAnnotation(Override.class) .addModifiers(PUBLIC) .addParameter(objectParamSpec); // 添加参数 TypeElement parent = entry.getKey(); List 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的源码!以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持创新互联。