ARouter原始碼解析04-interceptor攔截器
上篇文章我們分析了ARouter的路由跳轉,這篇文章我們來分析interceptor攔截器。
首先,同樣在IDE編譯過程中,攔截器也會產生相應的檔案。(詳見ARouter原始碼解析01-編譯生成檔案)
public class ARouter$$Interceptors$$app implements IInterceptorGroup { @Override public void loadInto(Map<Integer, Class<? extends IInterceptor>> interceptors) { interceptors.put(3, Test2Interceptor.class); interceptors.put(5, Test3Interceptor.class); interceptors.put(7, Test1Interceptor.class); } }
可以看到,這裡根據priority將Intercepter按照級別進行排序,級別從高到第依次put到interceptors集合中。那麼,這些intercepter是在什麼地方載入到記憶體中的呢?
同時,我們知道,攔截器有個init()方法,會在程式初始化的時候,進行呼叫,那麼,是在哪裡執行攔截器的init()方法的呢?
再回到ARouter.init()來看
public static void init(Application application) { //... hasInit = _ARouter.init(application); if (hasInit) { _ARouter.afterInit(); } //...
}
這裡有個afterInit方法,我們跟進去看下
static void afterInit() {
// Trigger interceptor init, use byName.
interceptorService = (InterceptorService) ARouter.getInstance().build("/arouter/service/interceptor").navigation();
}
這裡,通過路由跳轉,呼叫了InterceptorServiceImpl,但是在路由app模組build檔案中,並沒有/arouter/service/interceptor這個路由表單,那麼ARouter這裡是通過怎麼跳轉的呢?
原來,在aroute-api中,還有個arouter的build檔案,在這個檔案下,有著和app模組下build包名相同的ARouter開頭的幾個檔案(故ARouter.init的時候,也會把這幾個路由表單載入進去)
package com.alibaba.android.arouter.routes;
public class ARouter$$Group$$arouter implements IRouteGroup {
@Override
public void loadInto(Map<String, RouteMeta> atlas) {
atlas.put("/arouter/service/autowired", RouteMeta.build(RouteType.PROVIDER, AutowiredServiceImpl.class, "/arouter/service/autowired", "arouter", null, -1, -2147483648));
atlas.put("/arouter/service/interceptor", RouteMeta.build(RouteType.PROVIDER, InterceptorServiceImpl.class, "/arouter/service/interceptor", "arouter", null, -1, -2147483648));
}
}
我們再來在InterceptorServiceImpl,首先會在navigation的時候呼叫 LogisticsCenter.completion從而呼叫provider.init()方法進行初始化。
@Override
public void init(final Context context) {
LogisticsCenter.executor.execute(new Runnable() {
@Override
public void run() {
if (MapUtils.isNotEmpty(Warehouse.interceptorsIndex)) {
for (Map.Entry<Integer, Class<? extends IInterceptor>> entry : Warehouse.interceptorsIndex.entrySet()) {
Class<? extends IInterceptor> interceptorClass = entry.getValue();
try {
IInterceptor iInterceptor = interceptorClass.getConstructor().newInstance();
iInterceptor.init(context);
Warehouse.interceptors.add(iInterceptor);
} catch (Exception ex) {
throw new HandlerException(TAG + "ARouter init interceptor error! name = [" + interceptorClass.getName() + "], reason = [" + ex.getMessage() + "]");
}
}
interceptorHasInit = true;
synchronized (interceptorInitLock) {
interceptorInitLock.notifyAll();
}
}
}
});
}
可以發現,大體的,就是通過執行緒池.execute(),在非同步執行緒中,獲取所有的攔截器IInterceptor,呼叫他們的init方法,並把攔截器新增到Warehouse.interceptors集合中。
知道了
接著,繼續在navigation方法中,如果沒有把postcard.isGreenChannel設為true,那麼呼叫interceptorService.doInterceptions執行攔截器,處理是否攔截。
完成了攔截器的init(),再來看navigation的時候,攔截器的攔截,
final class _ARouter {
protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
LogisticsCenter.completion(postcard);
//isGreenChannel為ture,說明不需要interceptor,要跳過interceptor
if (!postcard.isGreenChannel()) {
interceptorService.doInterceptions(postcard, new InterceptorCallback() {
@Override
public void onContinue(Postcard postcard) {
_navigation(context, postcard, requestCode, callback);
}
@Override
public void onInterrupt(Throwable exception) {
if (null != callback) {
callback.onInterrupt(postcard);
}
}
});
} else {
return _navigation(context, postcard, requestCode, callback);
}
return null;
}
}
來看doInterceptions(),這裡進行攔截器的攔截,會遍歷攔截器列表,並呼叫攔截器的process(),最終,根據結果回撥onContinue或onInterrupt來繼續navigation或終止navigation。
@Override
public void doInterceptions(final Postcard postcard, final InterceptorCallback callback) {
// 檢查攔截器列表是否為空
if (CollectionUtils.isNotEmpty(Warehouse.interceptors)) {
// 等待攔截器服務完成初始化
// ......
LogisticsCenter.executor.execute(new Runnable() {
@Override
public void run() {
// CountDown倒數計數器
CancelableCountDownLatch interceptorCounter = new CancelableCountDownLatch(Warehouse.interceptors.size());
try {
// 在另一個執行緒中遞迴依次執行攔截器操作
_excute(0, interceptorCounter, postcard);
// 等待超時
interceptorCounter.await(postcard.getTimeout(), TimeUnit.SECONDS);
// 倒數計時器不為0,表示還有攔截器未執行完成
if (interceptorCounter.getCount() > 0) { // Cancel the navigation this time, if it hasn't return anythings.
callback.onInterrupt(new HandlerException("The interceptor processing timed out."));
} else if (null != postcard.getTag()) { // Maybe some exception in the tag.
callback.onInterrupt(new HandlerException(postcard.getTag().toString()));
} else {
callback.onContinue(postcard);
}
} catch (Exception e) {
callback.onInterrupt(e);
}
}
});
} else {
callback.onContinue(postcard);
}
}
/**
* Excute interceptor
*
* @param index current interceptor index
* @param counter interceptor counter
* @param postcard routeMeta
*/
private static void _excute(final int index, final CancelableCountDownLatch counter, final Postcard postcard) {
if (index < Warehouse.interceptors.size()) {
IInterceptor iInterceptor = Warehouse.interceptors.get(index);
iInterceptor.process(postcard, new InterceptorCallback() {
@Override
public void onContinue(Postcard postcard) {
// Last interceptor excute over with no exception.
counter.countDown();
_excute(index + 1, counter, postcard); // When counter is down, it will be execute continue ,but index bigger than interceptors size, then U know.
}
@Override
public void onInterrupt(Throwable exception) {
// Last interceptor excute over with fatal exception.
postcard.setTag(null == exception ? new HandlerException("No message.") : exception.getMessage()); // save the exception message for backup.
counter.cancel();
}
});
}
}
至此,即完成了interceptor的攔截,下篇文章,我們來解析ARouter的自動注入引數的功能。