阿里路由框架ARouter 源碼解析之Compiler
前段時(shí)間,公司項(xiàng)目在做組件化重構(gòu),過程中當(dāng)然會(huì)有很多痛點(diǎn)。
組件化最重要的是根據(jù)項(xiàng)目和業(yè)務(wù)進(jìn)行分模塊,至于模塊的粒度就看大家自己來把控了!
這里要說的就是模塊之間的數(shù)據(jù)傳輸問題
組件化之后,各個(gè)模塊不相互依賴,那么怎么相互跳轉(zhuǎn)和傳遞數(shù)據(jù)呢?
答案就是通過隱式Intent 的方式來跳轉(zhuǎn)和傳遞數(shù)據(jù)。
以往的顯示Intent 跳轉(zhuǎn),會(huì)存在類直接依賴的問題,這樣會(huì)導(dǎo)致耦合性非常嚴(yán)重;相比而言,隱式Intent則不需要類之間的直接依賴,但是會(huì)出現(xiàn)規(guī)則集中式管理,擴(kuò)展性比較差。
所以在調(diào)研期間就發(fā)現(xiàn)阿里開源了ARouter–路由框架。
ARouter的好處我這里就不多說,大家可以去看官方文檔或者去github上看README。
【https://github.com/alibaba/ARouter】
接下來會(huì)分為若干篇blog來分析一下ARouter的源碼!
看了ARouter的源碼就會(huì)發(fā)現(xiàn),它提供了兩個(gè)SDK,一個(gè)是API,一個(gè)Compiler。
- Compiler SDK 是用于編譯器生成相關(guān)類文件的。
- API SDK 是用在運(yùn)行期間路由跳轉(zhuǎn)等作用的。

這里先說說Compiler層SDK。
RouteProcessor 路由路徑處理器
InterceptorProcessor 攔截器處理器
AutowireProcessor 自動(dòng)裝配處理器
注解處理器的處理流程

(圖片轉(zhuǎn)自網(wǎng)絡(luò))
實(shí)際上,Compiler SDK 只是處根據(jù)掃描到的注解生成相應(yīng)的映射(java)文件。
最后一步通過固定包名加載映射文件是由API SDK來做的。
以官方demo為例來說:

上圖所示就是ARouter在編譯期間生成的類文件。
- 紅色標(biāo)注的是 RouteProcessor 生成的類文件
- 藍(lán)色標(biāo)注的是 InterceptorProcessor 生成的類文件
- 橙色標(biāo)書的是 AutowiredProcessor 生成的類文件
arouter-compiler的目錄結(jié)構(gòu)如下:

- processor包下面是注解處理器
- utils包下面是相關(guān)工具類
下面分別說說這三種注解處理器:
用過編譯時(shí)注解的朋友們都知道,注解處理器需要繼承AbstractProcessor ,主要涉及的函數(shù)有 init(),process() 這兩個(gè)。
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,則會(huì)拋出異常。
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注解的時(shí)候,按照官方文檔是需要在每個(gè)module里面的build.gradle中配置如下信息:
javaCompileOptions {
annotationProcessorOptions {
arguments = [ moduleName : project.getName() ]
}
}
配置這個(gè)屬性的目的,就是為了在編譯期間生成相關(guān)module下的文件和存儲(chǔ)文件名稱。
process()
一般在process()函數(shù)中做的操作如下:
- 遍歷注解的元素
- 檢驗(yàn)元素是否符合要求(過濾元素)
- 獲取輸出類參數(shù)
- 生成映射文件(java文件)
- 錯(cuò)誤處理
@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... <<<");
// 調(diào)用arseRoute()函數(shù)進(jìn)行處理獲取的注解元素集合
this.parseRoutes(routeElements);
} catch (Exception e) {
logger.error(e);
}
// 如果有Route元素的注解,并且處理過程中無異常則返回true
return true;
}
// 否則返回false
return false;
}
parseRoutes()
這個(gè)函數(shù)的代碼有點(diǎn)長,大家耐心看!
// 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用來創(chuàng)建類型對象,例如下面
```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封裝了路由相關(guān)的信息
```Map<String, RouteMeta>```
*/
ParameterizedTypeName inputMapTypeOfGroup = ParameterizedTypeName.get(
ClassName.get(Map.class),
ClassName.get(String.class),
ClassName.get(RouteMeta.class)
);
/*
創(chuàng)建輸入?yún)?shù)
*/
// 1。 生成的參數(shù):Map<String, Class<? extends IRouteGroup>> routes
ParameterSpec rootParamSpec = ParameterSpec.builder(inputMapTypeOfRoot, "routes").build(); // 第一個(gè)參數(shù)表示參數(shù)類型,第二個(gè)函數(shù)表示參數(shù)名稱
// 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用來創(chuàng)建方法
// 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); // 參數(shù)
// 創(chuàng)建出來的函數(shù)如下
/**
* @Override
* public void loadInto(Map<String, Class<? extends IRouteGroup>> routes) { }
*/
//
// 接下來的代碼就是遍歷注解元素,進(jìn)行分組,進(jìn)而聲稱java文件
for (Element element : routeElements) { // 遍歷每個(gè)元素
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支持寫別名,當(dāng)指定name屬性之后,就會(huì)以name為準(zhǔn),否則以field的名字為準(zhǔn)。
// TypeUtils是自定義工具類,用來判斷field的數(shù)據(jù)類型的,轉(zhuǎn)換成int值。
paramsType.put(StringUtils.isEmpty(paramConfig.name()) ? field.getSimpleName().toString() : paramConfig.name(), typeUtils.typeExchange(field));
}
// 構(gòu)建一條路由信息,將字段注解信息保存進(jìn)去
routeMete = new RouteMeta(route, element, RouteType.ACTIVITY, paramsType);
}
// 如果是IProvider類型的注解,則直接創(chuàng)建一條PROVIDER類型的路由信息
else if (types.isSubtype(tm, iProvider)) {
routeMete = new RouteMeta(route, element, RouteType.PROVIDER, null);
}
// 如果是Service類型的注解,則直接創(chuàng)建一條Service類型的路由信息
else if (types.isSubtype(tm, type_Service)) { // Service
routeMete = new RouteMeta(route, element, RouteType.parse(Service), null);
}
// 如果是fragmentTmV4類型的注解,則直接創(chuàng)建一條Fragment類型的路由信息
else if (types.isSubtype(tm, fragmentTm) || types.isSubtype(tm, fragmentTmV4)) {
routeMete = new RouteMeta(route, element, RouteType.parse(FRAGMENT), null);
}
// 將路由信息進(jìn)行分組 (每個(gè)路由信息對象中都保存著它所屬的組別信息,在調(diào)用categories()函數(shù)之前所有的組別信息都是默認(rèn)值"" )
categories(routeMete);
}
// 第一次遍歷之前,已經(jīng)創(chuàng)建了ROOT類的loadInto函數(shù)
// 下面開始創(chuàng)建Provider類的loadInto函數(shù)
MethodSpec.Builder loadIntoMethodOfProviderBuilder = MethodSpec.methodBuilder(METHOD_LOAD_INTO)
.addAnnotation(Override.class)
.addModifiers(PUBLIC)
.addParameter(providerParamSpec);
// 創(chuàng)建出來的函數(shù)如下
/**
* @Override
* public void loadInto(Map<String, RouteMeta> providers) { }
*/
// 接著,遍歷所有在 categories(routeMete); 得到的所有組別
for (Map.Entry<String, Set<RouteMeta>> entry : groupMap.entrySet()) {
String groupName = entry.getKey();
// 創(chuàng)建分組類的函數(shù) -- loadInto(Map<String, RouteMeta> atlas)
MethodSpec.Builder loadIntoMethodOfGroupBuilder = MethodSpec.methodBuilder(METHOD_LOAD_INTO)
.addAnnotation(Override.class)
.addModifiers(PUBLIC)
.addParameter(groupParamSpec);
// 往組別函數(shù)loadInto中添加數(shù)據(jù)
Set<RouteMeta> groupData = entry.getValue();
// PROVIDERL 類型的數(shù)據(jù)需要特殊處理
for (RouteMeta routeMeta : groupData) {
switch (routeMeta.getType()) {
case PROVIDER:
List<? extends TypeMirror> interfaces = ((TypeElement) routeMeta.getRawType()).getInterfaces();
// 遍歷當(dāng)前類的接口
for (TypeMirror tm : interfaces) {
// 如果當(dāng)前類直接實(shí)現(xiàn)了IProvider接口
if (types.isSameType(tm, iProvider)) {
// 這種情況下,在loadInfo()函數(shù)里面添加的語句類似于:
// singleService直接實(shí)現(xiàn)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()函數(shù)里面添加的語句類似于:
// singleService直接實(shí)現(xiàn)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函數(shù)里面添加一個(gè)語句
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) // 作用域?yàn)閜ublic
.addMethod(loadIntoMethodOfGroupBuilder.build()) // 添加函數(shù)(包括了函數(shù)里面的代碼塊)
.build()
).build().writeTo(mFiler);
// 將組名和組文件名放到map中,方便按需加載
rootMap.put(groupName, groupFileName);
}
// .................................................................... //
// 經(jīng)過了上面的for循環(huán),生成了如 ARouter$$Group$$service.java 和ARouter$$Group$$test.java 文件,它們所在的包是 com.alibaba.android.arouter.routes。
if (MapUtils.isNotEmpty(rootMap)) {
// 遍歷這些group,進(jìn)而生成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()));
// 每一個(gè)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()
下面來看一下怎么講路由進(jìn)行分組的
private void categories(RouteMeta routeMete) {
// 首先去驗(yàn)證這條路由信息
if (routeVerify(routeMete)) {
// 嘗試從groupMap中通過group名稱獲取路由信息
Set<RouteMeta> routeMetas = groupMap.get(routeMete.getGroup());
if (CollectionUtils.isEmpty(routeMetas)) { // 如果map中沒有相關(guān)記錄,則表示這個(gè)組別還未添加到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 {
// 驗(yàn)證路由信息不正確是會(huì)在編譯期間輸出錯(cuò)誤日志
logger.warning(">>> Route meta verify error, group is " + routeMete.getGroup() + " <<<");
}
}
routeVerify()
// 驗(yàn)證路由信息的正確性
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;
}
// 沒有分組時(shí),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;
}
通過上面的分析可以得到以下幾點(diǎn):
配置Route注解時(shí),路徑不允許為空且必須以“/”開頭
RouteProcessor注解處理器生成的文件由三種:
1. ARouter$$Group$$xxx (可能有多個(gè))
2. ARouter$$Providers$$xxx (只有一個(gè))
3. ARouter$$Root$$xxx (只有一個(gè))
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)) { // 做驗(yàn)證
Interceptor interceptor = element.getAnnotation(Interceptor.class);
// 嘗試從攔截器結(jié)合中根據(jù)優(yōu)先級獲取
Element lastInterceptor = interceptors.get(interceptor.priority());
// 如果是已經(jīng)存在相同優(yōu)先級的攔截器,就會(huì)拋出異常
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);
/**
* 創(chuàng)建類型對象
*
* ```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))
)
);
// 構(gòu)建輸入?yún)?shù)
ParameterSpec tollgateParamSpec = ParameterSpec.builder(inputMapTypeOfTollgate, "interceptors").build();
// 創(chuàng)建函數(shù) : 'loadInto'
MethodSpec.Builder loadIntoMethodOfTollgateBuilder = MethodSpec.methodBuilder(METHOD_LOAD_INTO)
.addAnnotation(Override.class)
.addModifiers(PUBLIC)
.addParameter(tollgateParamSpec);
// 遍歷攔截器結(jié)合,往loadInto函數(shù)中添加語句
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()
// 驗(yàn)證注解元素是否合格
private boolean verify(Element element) {
Interceptor interceptor = element.getAnnotation(Interceptor.class);
return null != interceptor && ((TypeElement)element).getInterfaces().contains(iInterceptor);
}
通過上面的分析可以得到以下幾點(diǎn):
不能設(shè)置相同優(yōu)先級的攔截器,否則會(huì)拋出異常
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函數(shù)主要關(guān)注兩點(diǎn) 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();
// 構(gòu)建輸入?yún)?shù)
ParameterSpec objectParamSpec = ParameterSpec.builder(TypeName.OBJECT, "target").build();
// 遍歷分組的集合
if (MapUtils.isNotEmpty(parentAndChild)) {
for (Map.Entry<TypeElement, List<Element>> entry : parentAndChild.entrySet()) {
// 構(gòu)建函數(shù) : 'inject'
MethodSpec.Builder injectMethodBuilder = MethodSpec.methodBuilder(METHOD_INJECT)
.addAnnotation(Override.class)
.addModifiers(PUBLIC)
.addParameter(objectParamSpec); // 添加參數(shù)
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);
// 構(gòu)建SerializationService 字段
FieldSpec jsonServiceField = FieldSpec.builder(TypeName.get(type_JsonService.asType()), "serializationService", Modifier.PRIVATE).build();
// 添加字段
helper.addField(jsonServiceField);
// inject函數(shù)中添加語句
// serializationService = ARouter.getInstance().navigation(SerializationService.class);
injectMethodBuilder.addStatement("serializationService = $T.getInstance().navigation($T.class);", ARouterClass, ClassName.get(type_JsonService));
// 轉(zhuǎn)換對象
// 比如: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類型時(shí),通過 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() 函數(shù)
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);
}
}
總結(jié)
至此,ARouter之Compiler SDK中的三種注解處理器都分析完畢!
接下來的文章開始分析API SDK的源碼!以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android自定義實(shí)現(xiàn)一個(gè)省份簡稱鍵盤
這篇文章主要為大家詳細(xì)介紹了Android如何自定義實(shí)現(xiàn)一個(gè)省份簡稱鍵盤,可以用在車牌輸入等地方,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-06-06
Android使用recyclerview打造真正的下拉刷新上拉加載效果
這篇文章先介紹如何使用這個(gè)recyclerview,WZMRecyclerview 是一個(gè)集成了 下拉刷新、上拉加載、滑到底部自動(dòng)加載、添加刪除頭尾部 四個(gè)主要功能的recyclerview,需要的朋友可以參考下2016-11-11
Android7.0 MTK設(shè)置默認(rèn)桌面
這篇文章主要為大家詳細(xì)介紹了Android7.0 MTK設(shè)置默認(rèn)桌面,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-07-07
Android仿XListView支持下拉刷新和上劃加載更多的自定義RecyclerView
這篇文章主要介紹了仿XListView支持下拉刷新和上劃加載更多的自定義RecyclerView的實(shí)例代碼,非常不錯(cuò),具有參考價(jià)值,感興趣的朋友可以參考下2016-05-05
Kotlin與Java相互調(diào)用的完整實(shí)例
Kotlin的設(shè)計(jì)過程中就考慮到了與Java的互操作性,在Kotlin中可以直接調(diào)用既有的Java代碼,反過來在Java中也可以很流暢地使用Kotlin代碼,這篇文章主要給大家介紹了關(guān)于Kotlin與Java相互調(diào)用的相關(guān)資料,需要的朋友可以參考下2021-12-12
Android Studio中引入Lambda表達(dá)式的方法
這篇文章主要給大家介紹了在Android Studio中引入Lambda表達(dá)式的方法,文中通過圖文介紹的非常詳細(xì),對大家具有一定的參考價(jià)值,需要的朋友們下面來一起看看吧。2017-03-03
Android基于OpenCV實(shí)現(xiàn)霍夫直線檢測
霍夫變換利用點(diǎn)與線之間的對偶性,將圖像空間中直線上離散的像素點(diǎn)通過參數(shù)方程映射為霍夫空間中的曲線,并將霍夫空間中多條曲線的交點(diǎn)作為直線方程的參數(shù)映射為圖像空間中的直線。給定直線的參數(shù)方程,可以利用霍夫變換來檢測圖像中的直線。本文簡單講解Android的實(shí)現(xiàn)2021-06-06
Android編程簡單獲取網(wǎng)絡(luò)上的圖片
這篇文章主要介紹了Android編程簡單獲取網(wǎng)絡(luò)上的圖片,結(jié)合實(shí)例形式分析了Android獲取網(wǎng)絡(luò)圖片及加載顯示的相關(guān)操作步驟與注意事項(xiàng),需要的朋友可以參考下2016-10-10

