前段时间,公司项目在做组件化重构,过程中当然会有很多痛点。
组件化最重要的是根据项目和业务进行分模块,至于模块的粒度就看大家自己来把控了!
这里要说的就是模块之间的数据传输问题
组件化之后,各个模块不相互依赖,那么怎么相互跳转和传递数据呢?
答案就是通过隐式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
类的继承信息:
1
2
3
4
5
|
@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()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
// 初始化处理器 @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. <<<" ); } |
1
2
|
// Consts.java public static final String KEY_MODULE_NAME = "moduleName" ; |
在使用ARouter注解的时候,按照官方文档是需要在每个module里面的build.gradle中配置如下信息:
1
2
3
4
5
|
javaCompileOptions { annotationProcessorOptions { arguments = [ moduleName : project.getName() ] } } |
配置这个属性的目的,就是为了在编译期间生成相关module下的文件和存储文件名称。
process()
一般在process()函数中做的操作如下:
- 遍历注解的元素
- 检验元素是否符合要求(过滤元素)
- 获取输出类参数
- 生成映射文件(java文件)
- 错误处理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
@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()
这个函数的代码有点长,大家耐心看!
1
2
3
4
5
6
7
8
9
10
11
12
13
|
// 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" ; |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
|
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()
下面来看一下怎么讲路由进行分组的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
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()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
// 验证路由信息的正确性 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
1
2
3
4
5
|
@AutoService (Processor. class ) @SupportedOptions (KEY_MODULE_NAME) @SupportedSourceVersion (SourceVersion.RELEASE_7) @SupportedAnnotationTypes (ANNOTATION_TYPE_INTECEPTOR) public class InterceptorProcessor extends AbstractProcessor |
init()
1
2
3
4
5
6
7
8
|
@Override public synchronized void init(ProcessingEnvironment processingEnv) { super .init(processingEnv); // ... 省略代码与RouteProcressor基本一样 iInterceptor = elementUtil.getTypeElement(Consts.IINTERCEPTOR).asType(); } |
process()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
@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()
1
|
private Map<Integer, Element> interceptors = new TreeMap<>(); |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
|
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()
1
2
3
4
5
|
// 验证注解元素是否合格 private boolean verify(Element element) { Interceptor interceptor = element.getAnnotation(Interceptor. class ); return null != interceptor && ((TypeElement)element).getInterfaces().contains(iInterceptor); } |
通过上面的分析可以得到以下几点:
不能设置相同优先级的拦截器,否则会抛出异常
InterceptorProcessor生成的类文件格式为:ARouter$$Interceptors$$xxx
AutowiredProcessor
1
2
3
4
5
|
@AutoService (Processor. class ) @SupportedOptions (KEY_MODULE_NAME) @SupportedSourceVersion (SourceVersion.RELEASE_7) @SupportedAnnotationTypes ({ANNOTATION_TYPE_AUTOWIRED}) public class AutowiredProcessor extends AbstractProcessor |
init()
1
2
3
4
5
6
7
8
9
10
11
12
|
@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()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
// 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
1
|
private Map<TypeElement, List<Element>> parentAndChild = new HashMap<>(); |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
// 将注解元素分组 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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
|
// 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文件举例如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
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的源码!以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:https://blog.csdn.net/crazy1235/article/details/77126904