1. 程式人生 > >ARouter原始碼解析04-interceptor攔截器

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的自動注入引數的功能。