文章

Arouter原理

Arouter原理

ARouter 架构原理

t6qv2

Compiler(编译器)

最基础的就是 Compiler 这个 SDK,主要是用来在编译期间处理注解`@Route/@Interceptor/@Autowired 三个注解,在编译期间自动注册注解标注的类,成员变量等。

  1. @Route 生成路由信息,生成在 build/generated/source/kapt/debug/com.alibaba.android.arouter.routes/,一个 group 一个类。

ez7ib

  1. @Interceptor 生成拦截器信息

s6jij

  1. @Autowired 依赖注入使用,类似于 ButterKnife 的 @Bind

od7ix

API(用户在运行期使用)

  1. Launcher 这一层只有 ARouter 和 _ ARouter,ARouter 就是我们需要打交道的接口,这里使用了代理模式,实际 ARouter 是通过 _ ARouter 进行工作。
  2. 第二层也是绿色的,用户也是可以调用到,这里主要是提供接口,我们可以扩展服务,比如拦截器服务,成员变量装配服务等,Template 主要是提供模版接口,这个 SDK 会在编译期生成一些映射文件,而这些映射文件会按照 Template 组件中提供的模板来生成,这样按照一定的规则和约束生成映射文件也方便 Route 在运行的时候进行读取。
  3. Warehouse 类似一个仓库,主要存储 ARouter 在运行期间加载的一些配置文件以及映射关系(存储页面路由/Provider/Interceptor 映射关系)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Warehouse {
    // Cache route and metas
    static Map<String, Class<? extends IRouteGroup>> groupsIndex = new HashMap<>();
    static Map<String, RouteMeta> routes = new HashMap<>(); // 页面路由/Fragment等,按group来加载

    // Cache provider
    static Map<Class, IProvider> providers = new HashMap<>(); // 服务提供Provider
    static Map<String, RouteMeta> providersIndex = new HashMap<>();

    // Cache interceptor
    static Map<Integer, Class<? extends IInterceptor>> interceptorsIndex = new UniqueKeyTreeMap<>("More than one interceptors use same priority [%s]");
    static List<IInterceptor> interceptors = new ArrayList<>(); // 拦截器

    static void clear() {
        routes.clear();
        groupsIndex.clear();
        providers.clear();
        providersIndex.clear();
        interceptors.clear();
        interceptorsIndex.clear();
    }
}
  1. Thread 则是提供了线程池,因为存在多个拦截器的时候以及跳转过程中都是需要异步执行的。
  2. Logistics Center。从名字上翻译就是物流中心,整个 SDK 的流转以及内部调用最终都会下沉到这一层。(和编译相关路由配置都在这里加载)

整个框架分层仔细,各个层之间分工明确。与编译期间映射关系打交道的工作都下层到 LogisticsCenter,与用户打交道的 API 都在 ARouter 中。

ARouter 源码分析

ARouter 基本使用

  • Activity 跳转
1
ARouter.getInstance().build("/test/activity2").withString("name", "老王").navigation();
  • 获取服务功能
1
2
3
4
// ByClass
ARouter.getInstance().navigation(HelloService.class).sayHello("mike");
// ByName
((HelloService) ARouter.getInstance().build("/yourservicegroupname/hello").navigation()).sayHello("mike");

ARouter 源码分析

wm9px

Init 流程

init 逻辑

入口:

1
2
3
4
5
6
7
8
9
10
11
ARouter.init(getApplication());
// ARouter
public static void init(Application application) {
    if (!hasInit) {
        logger = _ARouter.logger;
        hasInit = _ARouter.init(application); // hasInit变量用于保证初始化代码只执行一次
        if (hasInit) {
            _ARouter.afterInit();
        }
    }
}

ARouter 是外观模式的门面,实现逻辑在 _ARouter 类中,便于解藕。
接着看 _ARouter.init()

1
2
3
4
5
6
7
protected static synchronized boolean init(Application application) {
    mContext = application;
    LogisticsCenter.init(mContext, executor);
    hasInit = true;
    mHandler = new Handler(Looper.getMainLooper());
    return true;
}
  1. new 了一个 Handler(Looper 是主线程 )
  2. 初始化逻辑交给了 LogisticsCenter.init()

LogisticsCenter

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
public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException {
    mContext = context;
    executor = tpe;
    try {
        // 通过arouter-auto-register插件加载路由表
        loadRouterMap();
        if (registerByPlugin) { // 通过arouter-auto-register插件加载路由表
            logger.info(TAG, "Load router map by arouter-auto-register plugin.");
        } else { // App启动时动态扫描dex
            Set<String> routerMap;

            // It will rebuild router map every times when debuggable.
            if (ARouter.debuggable() || PackageUtils.isNewVersion(context)) { // 如果是debug版或是新的版本(即debug包每次初始化都会rebuild路由表)
                // 遍历所有dex文件,找到经过APT + JavaPoet处理生成的文件,并且将文件存到Map中
                routerMap = ClassUtils.getFileNameByPackageName(mContext, ROUTE_ROOT_PAKCAGE); // getFileNameByPackageName()方法返回所有满足需求的类名
                if (!routerMap.isEmpty()) { // 路由表保存到本地缓存sp
                    context.getSharedPreferences(AROUTER_SP_CACHE_KEY, Context.MODE_PRIVATE).edit().putStringSet(AROUTER_SP_KEY_MAP, routerMap).apply();
                }
                PackageUtils.updateVersion(context);    // Save new version name when router map update finishes.
            } else { // 从本地sp缓存中加载
                routerMap = new HashSet<>(context.getSharedPreferences(AROUTER_SP_CACHE_KEY, Context.MODE_PRIVATE).getStringSet(AROUTER_SP_KEY_MAP, new HashSet<String>()));
            }
            
            // 根据全路径名去匹配生成的Java文件类型,并且通过反射创建这个类的实例,并调用它的loadInto方法
            for (String className : routerMap) {
                if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_ROOT)) {
                    // com.alibaba.android.arouter.routes.ARouter$$Root
                    ((IRouteRoot) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.groupsIndex);
                } else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_INTERCEPTORS)) {
                    // com.alibaba.android.arouter.routes.ARouter$$Interceptors
                    // Load interceptorMeta
                    ((IInterceptorGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.interceptorsIndex);
                } else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_PROVIDERS)) {
                    // com.alibaba.android.arouter.routes.ARouter$$Providers
                    // Load providerIndex
                    ((IProviderGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.providersIndex);
                }
            }
        }
 
        if (Warehouse.groupsIndex.size() == 0) {
            logger.error(TAG, "No mapping files were found, check your configuration please!");
        }

        if (ARouter.debuggable()) {
            logger.debug(TAG, String.format(Locale.getDefault(), "LogisticsCenter has already been loaded, GroupIndex[%d], InterceptorIndex[%d], ProviderIndex[%d]", Warehouse.groupsIndex.size(), Warehouse.interceptorsIndex.size(), Warehouse.providersIndex.size()));
        }
    } catch (Exception e) {
        throw new HandlerException(TAG + "ARouter init logistics center exception! [" + e.getMessage() + "]");
    }
}

LogisticsCenter 的 init() 方法主要做两件事:

  1. 找出 com.alibaba.android.arouter.routes 包下面所有的类名(这些是通过 apt 生成的),存到集合中。通过两种方式来获取,一种是在运行期间动态的遍历所有 dex 文件,另外一种是通过编译期间自定义插件通过 ASM 的方式把符合预期的类信息插入注册代码到 loadRouterMap 中。
  2. x8w2g
  3. 根据类名,通过反射创建这个类的实例并且调用这个对象的 loadInto 方法去初始化 Warehouse 里面的参数 (Root、Interceptor 和 Provider)

Warehouse

WareHouse 相当于 ARouter 的全局缓存:

1
2
3
4
5
6
7
8
9
10
11
12
//Warehouse.java
// Cache route and metas
static Map<String, Class<? extends IRouteGroup>> groupsIndex = new HashMap<>();
static Map<String, RouteMeta> routes = new HashMap<>();

// Cache provider
static Map<Class, IProvider> providers = new HashMap<>();
static Map<String, RouteMeta> providersIndex = new HashMap<>();

// Cache interceptor
static Map<Integer, Class<? extends IInterceptor>> interceptorsIndex = new UniqueKeyTreeMap<>("More than one interceptors use same priority [%s]");
static List<IInterceptor> interceptors = new ArrayList<>();
  1. groupsIndex
    key 为 group 名字,一般为 module 名,key 为 @Route 注解通过 apt 生成的 class
  2. routes
  3. providersIndex
  4. providers
  5. interceptorsIndex
  6. interceptors
  • 1、groupsIndex 对应 IRouteRoot
1
2
3
4
5
6
7
8
public class ARouter$$Root$$app implements IRouteRoot {
  @Override
  public void loadInto(Map<String, Class<? extends IRouteGroup>> routes) {
    routes.put("about", ARouter$$Group$$about.class);
    routes.put("home", ARouter$$Group$$home.class);
    routes.put("splash", ARouter$$Group$$splash.class);
  }
}

key 为 group 名称,官方推荐 group 名与当前模块名字相同,但是也可以一个模块设置多个分组;关于 value 是一个 Class 类型,它继承 IRouteGroup 接口,这个类是通过 APT 自动生成的,这个类记载了同个 Module 同个组名下所有被@Route 注解修饰的类信息

1
2
3
4
5
6
7
8
9
public class ARouter$$Group$$home implements IRouteGroup {
  @Override
  public void loadInto(Map<String, RouteMeta> atlas) {
    atlas.put("/home/dialog_provider", RouteMeta.build(RouteType.PROVIDER, HomePageDialogProvider.class, "/home/dialog_provider", "home", null, -1, -2147483648));
    atlas.put("/home/immersive_web", RouteMeta.build(RouteType.ACTIVITY, ImmersiveWebActivity.class, "/home/immersive_web", "home", new java.util.HashMap<String, Integer>(), -1, -2147483648));
    atlas.put("/home/tab", RouteMeta.build(RouteType.ACTIVITY, MainActivity.class, "/home/tab", "home", new java.util.HashMap<String, Integer>(), -1, 3));
    atlas.put("/home/web", RouteMeta.build(RouteType.ACTIVITY, SimpleWebActivity.class, "/home/web", "home", new java.util.HashMap<String, Integer>(), -1, -2147483648));
  }
}
  • key 为@Route 注解设置的路径,value 是 RouteMeta 对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class RouteMeta {
    private RouteType type;         // Type of route
    private Element rawType;        // Raw type of route
    private Class<?> destination;   // Destination
    private String path;            // Path of route
    private String group;           // Group of route
    private int priority = -1;      // The smaller the number, the higher the priority
    private int extra;              // Extra data
    private Map<String, Integer> paramsType;  // Param type
    private String name;
}

// 记录了路由类型,目标class等信息
public enum RouteType {
    ACTIVITY(0, "android.app.Activity"),
    SERVICE(1, "android.app.Service"),
    PROVIDER(2, "com.alibaba.android.arouter.facade.template.IProvider"),
    CONTENT_PROVIDER(-1, "android.app.ContentProvider"),
    BOARDCAST(-1, ""),
    METHOD(-1, ""),
    FRAGMENT(-1, "android.app.Fragment"),
    UNKNOWN(-1, "Unknown route type");
}

其他的一些 Group:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public interface IRouteRoot {
    void loadInto(Map<String, Class<? extends IRouteGroup>> routes);
}

public interface IRouteGroup {
    void loadInto(Map<String, RouteMeta> atlas);
}

public interface IInterceptorGroup {
    void loadInto(Map<Integer, Class<? extends IInterceptor>> interceptor);
}

public interface IProviderGroup {
    void loadInto(Map<String, RouteMeta> providers);
}
  • 2、providersIndex 对应 IProviderGroup
1
2
3
4
5
6
7
8
public class ARouter$$Providers$$m_room implements IProviderGroup {
  @Override
  public void loadInto(Map<String, RouteMeta> providers) {
    providers.put("club.jinmei.mgvoice.core.arouter.provider.family.IFamilyRecallProvider", RouteMeta.build(RouteType.PROVIDER, FamilyRecallProvider.class, "/room/family_recall_provider", "room", null, -1, -2147483648));
    providers.put("club.jinmei.mgvoice.core.arouter.provider.gift.IMGiftProvider", RouteMeta.build(RouteType.PROVIDER, GiftProvider.class, "/room/load_gift", "room", null, -1, -2147483648));
    providers.put("club.jinmei.mgvoice.core.arouter.provider.room.IRoomProvider", RouteMeta.build(RouteType.PROVIDER, RoomProviderImpl.class, "/room/room_provider", "room", null, -1, -2147483648));
  }
}

key 为 Provider 的全路径名,value 为 RouteMeta 对象

  • 3、interceptorsIndex 对应 IInterceptorGroup
1
2
3
4
5
6
7
8
9
public class ARouter$$Interceptors$$m_core implements IInterceptorGroup {
  @Override
  public void loadInto(Map<Integer, Class<? extends IInterceptor>> interceptors) {
    interceptors.put(1, ARouterLoginInterceptor.class);
    interceptors.put(2, ARouterMiniRoomInterceptor.class);
    interceptors.put(3, ARouterUpdateInterceptor.class);
    interceptors.put(4, RoomLockInterceptor.class);
  }
}

key 为拦截器的 priority,value 为 Interceptor 的 class

1
2
3
4
5
ARouter.getInstance()
    .build(ARouterConstants.Me.ROUTER_PATH_ACTIVITY_FEEDBACK)
    .withInt("reportFrom", 3/*ReportPostRequestBean.REPORT_FROM_VOICE_ROOM*/)
    .withString("feedbackUserId", uid)
    .navigation()

build 方法的真正实现也在 _ARouter 中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// ARouter
public Postcard build(String path) {
    return _ARouter.getInstance().build(path);
}
// _ARouter
protected Postcard build(String path, String group) {
    if (TextUtils.isEmpty(path) || TextUtils.isEmpty(group)) {
        throw new HandlerException(Consts.TAG + "Parameter is invalid!");
    } else {
        PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);
        if (null != pService) {
            path = pService.forString(path);
        }
        return new Postcard(path, group);
    }
}
  • 通过 path 和 group 创建了 Postcard 对象

Postcard

Postcard 明信片,路由的一些信息和参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// A container that contains the roadmap.
public final class Postcard extends RouteMeta {
    // Base
    private Uri uri;
    private Object tag;             // A tag prepare for some thing wrong.
    private Bundle mBundle;         // Data to transform
    private int flags = -1;         // Flags of route
    private int timeout = 300;      // Navigation timeout, TimeUnit.Second
    private IProvider provider;     // It will be set value, if this postcard was provider.
    private boolean greenChannel;
    private SerializationService serializationService;

    // Animation
    private Bundle optionsCompat;    // The transition animation of activity
    private int enterAnim = -1;
    private int exitAnim = -1;
}

而 navigation 最终会调用到 _ARouter 中的 navigation 方法:

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
// ARouter
public <T> T navigation(Class<? extends T> service) {
    return _ARouter.getInstance().navigation(service);
}
// _ARouter
protected <T> T navigation(Class<? extends T> service) {
    try {
        Postcard postcard = LogisticsCenter.buildProvider(service.getName());

        // Compatible 1.0.5 compiler sdk.
        // Earlier versions did not use the fully qualified name to get the service
        if (null == postcard) {
            // No service, or this service in old version.
            postcard = LogisticsCenter.buildProvider(service.getSimpleName());
        }

        if (null == postcard) {
            return null;
        }

        LogisticsCenter.completion(postcard);
        return (T) postcard.getProvider();
    } catch (NoRouteFoundException ex) {
        logger.warning(Consts.TAG, ex.getMessage());
        return null;
    }
}
  1. 通过 LogisticsCenter.completion 填充 Postcard
  2. 返回 postcard.getProvider(),其为 destination,在 LogisticsCenter.completion 会反射创建出来,然后缓存到 Warehouse.providers()
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
// ARouter
public Object navigation(Context mContext, Postcard postcard, int requestCode, NavigationCallback callback) {
    return _ARouter.getInstance().navigation(mContext, postcard, requestCode, callback);
}
// _ARouter
protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
    PretreatmentService pretreatmentService = ARouter.getInstance().navigation(PretreatmentService.class);
    if (null != pretreatmentService && !pretreatmentService.onPretreatment(context, postcard)) {
        // Pretreatment failed, navigation canceled.
        return null;
    }
    try {
        LogisticsCenter.completion(postcard); // 1
    } catch (NoRouteFoundException ex) {
        if (null != callback) { // 路由失败的callback
            callback.onLost(postcard);
        } else { // 路由失败降级服务
            DegradeService degradeService = ARouter.getInstance().navigation(DegradeService.class);
            if (null != degradeService) {
                degradeService.onLost(context, postcard);
            }
        }
        return null;
    }
    if (null != callback) { // 有可达路由
        callback.onFound(postcard);
    }
    if (!postcard.isGreenChannel()) {   // It must be run in async thread, maybe interceptor cost too mush time made ANR.
        // 拦截服务
        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;
}
  1. 调用 LogisticsCenter.completion 方法去从 WareHouse 中获取缓存数据填充当前的 Postcard
  2. 如果是 Green Channel,直接调用 _navigation()
  3. 如果不是 Green Channel,通过 InterceptorService 在子线程中进行拦截服务,然后 _navigation()
Postcard 信息完善

先看看 LogisticsCenter.completion

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
public synchronized static void completion(Postcard postcard) {
    RouteMeta routeMeta = Warehouse.routes.get(postcard.getPath()); // 从routes取出RouteMeata信息
    if (null == routeMeta) {    // Maybe its does't exist, or didn't load. // 不存在或未加载
        Class<? extends IRouteGroup> groupMeta = Warehouse.groupsIndex.get(postcard.getGroup());  // Load route meta.
        if (null == groupMeta) {
            throw new NoRouteFoundException(TAG + "There is no route match the path [" + postcard.getPath() + "], in group [" + postcard.getGroup() + "]");
        } else {
            // Load route and cache it into memory, then delete from metas.
            try {
                IRouteGroup iGroupInstance = groupMeta.getConstructor().newInstance();
                iGroupInstance.loadInto(Warehouse.routes);
                Warehouse.groupsIndex.remove(postcard.getGroup());
            } catch (Exception e) {
                throw new HandlerException(TAG + "Fatal exception when loading group meta. [" + e.getMessage() + "]");
            }
            completion(postcard);   // Reload
        }
    } else {
        postcard.setDestination(routeMeta.getDestination());
        postcard.setType(routeMeta.getType());
        postcard.setPriority(routeMeta.getPriority());
        postcard.setExtra(routeMeta.getExtra());

        Uri rawUri = postcard.getUri();
        if (null != rawUri) {   // Try to set params into bundle.
            Map<String, String> resultMap = TextUtils.splitQueryParameters(rawUri);
            Map<String, Integer> paramsType = routeMeta.getParamsType();

            if (MapUtils.isNotEmpty(paramsType)) {
                // Set value by its type, just for params which annotation by @Param
                for (Map.Entry<String, Integer> params : paramsType.entrySet()) {
                    setValue(postcard,
                            params.getValue(),
                            params.getKey(),
                            resultMap.get(params.getKey()));
                }

                // Save params name which need auto inject.
                postcard.getExtras().putStringArray(ARouter.AUTO_INJECT, paramsType.keySet().toArray(new String[]{}));
            }

            // Save raw uri
            postcard.withString(ARouter.RAW_URI, rawUri.toString());
        }

        switch (routeMeta.getType()) {
            case PROVIDER:  // if the route is provider, should find its instance
                // Its provider, so it must implement IProvider
                Class<? extends IProvider> providerMeta = (Class<? extends IProvider>) routeMeta.getDestination();
                IProvider instance = Warehouse.providers.get(providerMeta);
                if (null == instance) { // There's no instance of this provider
                    IProvider provider;
                    try {
                        provider = providerMeta.getConstructor().newInstance();
                        provider.init(mContext);
                        Warehouse.providers.put(providerMeta, provider);
                        instance = provider;
                    } catch (Exception e) {
                        throw new HandlerException("Init provider failed! " + e.getMessage());
                    }
                }
                postcard.setProvider(instance);
                postcard.greenChannel();    // Provider should skip all of interceptors
                break;
            case FRAGMENT:
                postcard.greenChannel();    // Fragment needn't interceptors
            default:
                break;
        }
    }
}
  1. 根据 path 去 Warehouse.routes 查找 RouteMeta,如果不存在,从 Warehouse.groupsIndex 中查找,找到通过反射创建实例,然后填充到 Warehouse.routes 中去;如果存在,看 2 步骤
  2. 根据获取到的 RouteMeta 将信息填充到 Postcard,FRAGMENT 和 PROVIDER 类型是绿色通道。
路由

接着看 _navigation() 逻辑:

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
private Object _navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
    final Context currentContext = null == context ? mContext : context;
    switch (postcard.getType()) {
        case ACTIVITY:
            // Build intent
            final Intent intent = new Intent(currentContext, postcard.getDestination());
            intent.putExtras(postcard.getExtras());

            // Set flags.
            int flags = postcard.getFlags();
            if (-1 != flags) {
                intent.setFlags(flags);
            } else if (!(currentContext instanceof Activity)) {    // Non activity, need less one flag.
                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            }

            // Set Actions
            String action = postcard.getAction();
            if (!TextUtils.isEmpty(action)) {
                intent.setAction(action);
            }

            // Navigation in main looper.
            runInMainThread(new Runnable() {
                @Override
                public void run() {
                    startActivity(requestCode, currentContext, intent, postcard, callback);
                }
            });

            break;
        case PROVIDER:
            return postcard.getProvider();
        case BOARDCAST:
        case CONTENT_PROVIDER:
        case FRAGMENT:
            Class fragmentMeta = postcard.getDestination();
            try {
                Object instance = fragmentMeta.getConstructor().newInstance();
                if (instance instanceof Fragment) {
                    ((Fragment) instance).setArguments(postcard.getExtras());
                } else if (instance instanceof android.support.v4.app.Fragment) {
                    ((android.support.v4.app.Fragment) instance).setArguments(postcard.getExtras());
                }

                return instance;
            } catch (Exception ex) {
                logger.error(Consts.TAG, "Fetch fragment instance error, " + TextUtils.formatStackTrace(ex.getStackTrace()));
            }
        case METHOD:
        case SERVICE:
        default:
            return null;
    }
    return null;
}
  1. ACTIVITY 类型,构建 Intent,在主线程中 startActivity
  2. PROVIDER 类型,直接调用 getProvider(),provider 是在 LogisticsCenter.completion 完成的,反射创建实例的
  3. BROADCAST、CONTENT_PROVIDER 和 FRAGMENT 类型,通过反射创建实例的
  4. 其他类型,方法 null

Inject 流程

1
ARouter.getInstance().inject(this);

最终会调用到 _ARouter 中的如下方法:

1
2
3
4
5
6
7
// _ARouter.java
static void inject(Object thiz) {
    AutowiredService autowiredService = ((AutowiredService) ARouter.getInstance().build("/arouter/service/autowired").navigation());
    if (null != autowiredService) {
        autowiredService.autowire(thiz);
    }
}

path 是 /arouter/service/autowired 对应的实例是 AutowiredServiceImpl,最终 inject 方法会调用到 AutowiredServiceImpl.autowire() 方法。

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
public interface AutowiredService extends IProvider {
    void autowire(Object instance);
}

@Route(path = "/arouter/service/autowired")
public class AutowiredServiceImpl implements AutowiredService {
    private LruCache<String, ISyringe> classCache;
    private List<String> blackList;

    @Override
    public void init(Context context) {
        classCache = new LruCache<>(66);
        blackList = new ArrayList<>();
    }

    @Override
    public void autowire(Object instance) {
        String className = instance.getClass().getName();
        try {
            if (!blackList.contains(className)) {
                ISyringe autowiredHelper = classCache.get(className);
                if (null == autowiredHelper) {  // No cache.
                    // SUFFIX_AUTOWIRED: 目标类名$$ARouter$$Autowired,如:MainActivity$$ARouter$$Autowired.java
                    autowiredHelper = (ISyringe) Class.forName(instance.getClass().getName() + SUFFIX_AUTOWIRED).getConstructor().newInstance();
                }
                autowiredHelper.inject(instance);
                classCache.put(className, autowiredHelper);
            }
        } catch (Exception ex) {
            blackList.add(className);    // This instance need not autowired.
        }
    }
}
  • 根据 inject 传入的 class 对象,构造 AutowiredProcessor 注解处理器自动生成的 Java 文件名,然后通过反射方式获取这个类的实例。

下面是 MainActivity 生成的自动注入代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class MainActivity$$ARouter$$Autowired implements ISyringe {
  private SerializationService serializationService;

  @Override
  public void inject(Object target) {
    serializationService = ARouter.getInstance().navigation(SerializationService.class);
    MainActivity substitute = (MainActivity)target;
    substitute.tabId = substitute.getIntent().getStringExtra("tab");
    substitute.page = substitute.getIntent().getStringExtra("page");
    substitute.isFormLogin = substitute.getIntent().getBooleanExtra("isFormLogin", substitute.isFormLogin);
    substitute.shouldJumpAdDeeplink = substitute.getIntent().getStringExtra("click_ad_deeplink");
    substitute.userAwardedBadge = ARouter.getInstance().navigation(IAwardedUserBadgeProvider.class);
  }
}

Interceptor 流程

在前面 init 流程初始化完成之后会调用 afterInit 去初始化拦截器

1
2
3
4
static void afterInit() {
    // Trigger interceptor init, use byName.
    interceptorService = (InterceptorService) ARouter.getInstance().build("/arouter/service/interceptor").navigation(); // 返回的是InterceptorServiceImpl实例
}

path:/arouter/service/interceptor 对应目标类 InterceptorServiceImpl

初始化 interceptors

在 navigation 流程在创建 IProvider 对象时候会调用它的 init 方法(LogisticsCenter.completion() 方法中)

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
// InterceptorServiceImpl.java
@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();
                }
            }
        }
    });
}
  • 根据 Warehouse.interceptorsIndex 去初始化 Warehouse.interceptors
  • 如果在 doInterceptions 进行拦截时,还未 init,会先 init,然后通过 interceptorInitLock 唤醒

doInterceptions 拦截逻辑

在 navigation 流程,构建完 Postcard 之后如果是非 IProvider 或者 Fragment 会去尝试判断是否拦截:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
    // ...
    try {
        LogisticsCenter.completion(postcard);
    } catch (NoRouteFoundException ex) {
        //...
    }
    // ...
    if (!postcard.isGreenChannel()) {   // It must be run in async thread, maybe interceptor cost too mush time made ANR.
        // interceptorService其实就是InterceptorServiceImpl实例
        interceptorService.doInterceptions(postcard, new InterceptorCallback() {
            @Override
            public void onContinue(Postcard postcard) {}
            @Override
            public void onInterrupt(Throwable exception) {}
        });
    } 
    // ...
}

调用了 InterceptorServiceImpl.doInterceptions 方法:

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
@Override
public void doInterceptions(final Postcard postcard, final InterceptorCallback callback) {
    if (null != Warehouse.interceptors && Warehouse.interceptors.size() > 0) {
        checkInterceptorsInitStatus();
        if (!interceptorHasInit) {
            callback.onInterrupt(new HandlerException("Interceptors initialization takes too much time."));
            return;
        }
        LogisticsCenter.executor.execute(new Runnable() {
            @Override
            public void run() {
                CancelableCountDownLatch interceptorCounter = new CancelableCountDownLatch(Warehouse.interceptors.size());
                try {
                    _excute(0, interceptorCounter, postcard);
                    interceptorCounter.await(postcard.getTimeout(), TimeUnit.SECONDS); // 在这阻塞者,直到调用了count次countDown()方法
                    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);
    }
}
private static void _execute(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(); // 执行了一个Interceptor后,countDown下
                _execute(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) {
                //...
                counter.cancel();
            }
        });
    }
}
  • 建一个与拦截器数量相同的 CancelableCountDownLatch 初始计数值,每放行一个拦截器就 countDown,并交给后一个拦截器,如果拦截则清 0 计数,并将拦截的 Throwable 存入 postcard 的 tag 字段,interceptorCounter.await(); 阻塞直到计数归 0 或者阻塞超时(默认是 300 秒),最后通过 interceptorCounter.getCount() 判断是否是超时,还是拦截或者放行。
  • 拦截的过程都是在子线程中处理,包括 Interceptor 的 process 也是在子线程调用的,因此,如果想要在拦截过程中展示 dialog 等都需要切换到主线程。

CancelableCountDownLatch,调用 await 方法后,会一直阻塞着,直到调用了 count 次 countDown 后,才会执行 await 后代码。

com.alibaba.arouter 插件分析

https://github.com/alibaba/ARouter/tree/develop/arouter-gradle-plugin

入口类 com.alibaba.android.arouter.register.launch.PluginLaunch

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class PluginLaunch implements Plugin<Project> {
    @Override
    public void apply(Project project) {
        def isApp = project.plugins.hasPlugin(AppPlugin)
        // only application module needs this plugin to generate register code
        if (isApp) {
            Logger.make(project)

            Logger.i('Project enable arouter-register plugin')

            def android = project.extensions.getByType(AppExtension)
            def transformImpl = new RegisterTransform(project) // 注册transform

            //init arouter-auto-register settings
            ArrayList<ScanSetting> list = new ArrayList<>(3)
            list.add(new ScanSetting('IRouteRoot'))
            list.add(new ScanSetting('IInterceptorGroup'))
            list.add(new ScanSetting('IProviderGroup'))
            RegisterTransform.registerList = list
            //register this plugin
            android.registerTransform(transformImpl)
        }
    }
}
  1. 只有 app module(应用了 com.android.application 插件的 module)才需要应用该插件
  2. 注册 RegisterTransform 一个 AGP 的 transform
  3. ScanSetting 是一些插件名、ARouter 类全路径等的一些配置

现在看看 RegisterTransform,重点看 transform(…) 方法

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
class RegisterTransform extends Transform {
    @Override
    void transform(Context context, Collection<TransformInput> inputs
                   , Collection<TransformInput> referencedInputs
                   , TransformOutputProvider outputProvider
                   , boolean isIncremental) throws IOException, TransformException, InterruptedException {

        Logger.i('Start scan register info in jar file.')

        long startTime = System.currentTimeMillis()
        boolean leftSlash = File.separator == '/'

        inputs.each { TransformInput input ->

            // scan all jars // 处理jar
            input.jarInputs.each { JarInput jarInput ->
                String destName = jarInput.name
                // rename jar files // 重命名
                def hexName = DigestUtils.md5Hex(jarInput.file.absolutePath)
                if (destName.endsWith(".jar")) {
                    destName = destName.substring(0, destName.length() - 4) // 取jar的name,不包括.jar后缀
                }
                // input file
                File src = jarInput.file
                // output file 输出路径,名字为:原有jar的name_全路径的md5值
                File dest = outputProvider.getContentLocation(destName + "_" + hexName, jarInput.contentTypes, jarInput.scopes, Format.JAR)

                // scan jar file to find classes
                if (ScanUtil.shouldProcessPreDexJar(src.absolutePath)) {
                    ScanUtil.scanJar(src, dest)
                }
                FileUtils.copyFile(src, dest)

            }
            // scan class files // 处理class
            input.directoryInputs.each { DirectoryInput directoryInput ->
                File dest = outputProvider.getContentLocation(directoryInput.name, directoryInput.contentTypes, directoryInput.scopes, Format.DIRECTORY)
                String root = directoryInput.file.absolutePath
                if (!root.endsWith(File.separator))
                    root += File.separator
                directoryInput.file.eachFileRecurse { File file ->
                    def path = file.absolutePath.replace(root, '')
                    if (!leftSlash) {
                        path = path.replaceAll("\\\\", "/")
                    }
                    if(file.isFile() && ScanUtil.shouldProcessClass(path)){
                        ScanUtil.scanClass(file)
                    }
                }

                // copy to dest
                FileUtils.copyDirectory(directoryInput.file, dest)
            }
        }

        Logger.i('Scan finish, current cost time ' + (System.currentTimeMillis() - startTime) + "ms")

        if (fileContainsInitClass) {
            registerList.each { ext ->
                Logger.i('Insert register code to file ' + fileContainsInitClass.absolutePath)

                if (ext.classList.isEmpty()) {
                    Logger.e("No class implements found for interface:" + ext.interfaceName)
                } else {
                    ext.classList.each {
                        Logger.i(it)
                    }
                    RegisterCodeGenerator.insertInitCodeTo(ext)
                }
            }
        }

        Logger.i("Generate code finish, current cost time: " + (System.currentTimeMillis() - startTime) + "ms")
    }
}
  1. 分别处理 jar 和源文件编译的 class,分别调用 ScanUtil.scanJarScanUtil.scanClass
  2. 遍历 registerList,调用 RegisterCodeGenerator.insertInitCodeTo()

先看 ScanUtil.scanClass

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
static void scanClass(InputStream inputStream) {
    ClassReader cr = new ClassReader(inputStream)
    ClassWriter cw = new ClassWriter(cr, 0)
    ScanClassVisitor cv = new ScanClassVisitor(Opcodes.ASM5, cw)
    cr.accept(cv, ClassReader.EXPAND_FRAMES)
    inputStream.close()
}
static class ScanClassVisitor extends ClassVisitor {
    ScanClassVisitor(int api, ClassVisitor cv) {
        super(api, cv)
    }
    void visit(int version, int access, String name, String signature,
               String superName, String[] interfaces) {
        super.visit(version, access, name, signature, superName, interfaces)
        RegisterTransform.registerList.each { ext ->
            if (ext.interfaceName && interfaces != null) {
                interfaces.each { itName ->
                    if (itName == ext.interfaceName) {
                        ext.classList.add(name)
                    }
                }
            }
        }
    }
}

RegisterTransform.registerList 为:

1
2
3
4
5
ArrayList<ScanSetting> list = new ArrayList<>(3)
list.add(new ScanSetting('IRouteRoot'))
list.add(new ScanSetting('IInterceptorGroup'))
list.add(new ScanSetting('IProviderGroup'))
RegisterTransform.registerList = list

扫描所有的 class,找到实现了上诉 3 个接口的类,添加到 ScanSetting.classList

1
2
// 存放扫描到实现了指定接口的所有class
ArrayList<String> classList = new ArrayList<>()

接口看 RegisterCodeGenerator.insertInitCodeTo()

1
2
3
4
5
6
7
8
static void insertInitCodeTo(ScanSetting registerSetting) {
    if (registerSetting != null && !registerSetting.classList.isEmpty()) {
        RegisterCodeGenerator processor = new RegisterCodeGenerator(registerSetting)
        File file = RegisterTransform.fileContainsInitClass
        if (file.getName().endsWith('.jar'))
            processor.insertInitCodeIntoJarFile(file)
    }
}

接着走到 insertInitCodeIntoJarFile() 方法:

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
private File insertInitCodeIntoJarFile(File jarFile) {
    if (jarFile) {
        def optJar = new File(jarFile.getParent(), jarFile.name + ".opt")
        if (optJar.exists())
            optJar.delete()
        def file = new JarFile(jarFile)
        Enumeration enumeration = file.entries()
        JarOutputStream jarOutputStream = new JarOutputStream(new FileOutputStream(optJar))

        while (enumeration.hasMoreElements()) {
            JarEntry jarEntry = (JarEntry) enumeration.nextElement()
            String entryName = jarEntry.getName()
            ZipEntry zipEntry = new ZipEntry(entryName)
            InputStream inputStream = file.getInputStream(jarEntry)
            jarOutputStream.putNextEntry(zipEntry)
            // 如果class name为com/alibaba/android/arouter/core/LogisticsCenter
            if (ScanSetting.GENERATE_TO_CLASS_FILE_NAME == entryName) {
                Logger.i('Insert init code to class >> ' + entryName)

                def bytes = referHackWhenInit(inputStream)
                jarOutputStream.write(bytes)
            } else {
                jarOutputStream.write(IOUtils.toByteArray(inputStream))
            }
            inputStream.close()
            jarOutputStream.closeEntry()
        }
        jarOutputStream.close()
        file.close()

        if (jarFile.exists()) {
            jarFile.delete()
        }
        optJar.renameTo(jarFile)
    }
    return jarFile
}

接着调用 referHackWhenInit() 方法:

1
2
3
4
5
6
7
8
//refer hack class when object init
    private byte[] referHackWhenInit(InputStream inputStream) {
    ClassReader cr = new ClassReader(inputStream)
    ClassWriter cw = new ClassWriter(cr, 0)
    ClassVisitor cv = new MyClassVisitor(Opcodes.ASM5, cw)
    cr.accept(cv, ClassReader.EXPAND_FRAMES)
    return cw.toByteArray()
}

现在看 MyClassVisitor:

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
class MyClassVisitor extends ClassVisitor {

    MyClassVisitor(int api, ClassVisitor cv) {
        super(api, cv)
    }

    void visit(int version, int access, String name, String signature,
               String superName, String[] interfaces) {
        super.visit(version, access, name, signature, superName, interfaces)
    }
    @Override
    MethodVisitor visitMethod(int access, String name, String desc,
                              String signature, String[] exceptions) {
        MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions)
        //generate code into this method
        if (name == ScanSetting.GENERATE_TO_METHOD_NAME) { // 如果是loadRouterMap方法
            mv = new RouteMethodVisitor(Opcodes.ASM5, mv)
        }
        return mv
    }
}

class RouteMethodVisitor extends MethodVisitor {

    RouteMethodVisitor(int api, MethodVisitor mv) {
        super(api, mv)
    }

    @Override
    void visitInsn(int opcode) {
        //generate code before return  // 在loadRouterMap方法return前
        if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN)) { 
            // classList就是刚刚扫描到的实现了指定接口的class集合
            extension.classList.each { name -> 
                name = name.replaceAll("/", ".")
                mv.visitLdcInsn(name)//类名
                // 生成调用LogisticsCenter.register的代码,传递的参数为name
                // generate invoke register method into LogisticsCenter.loadRouterMap()
                mv.visitMethodInsn(Opcodes.INVOKESTATIC
                        , ScanSetting.GENERATE_TO_CLASS_NAME
                        , ScanSetting.REGISTER_METHOD_NAME
                        , "(Ljava/lang/String;)V"
                        , false)
            }
        }
        super.visitInsn(opcode)
    }
    @Override
    void visitMaxs(int maxStack, int maxLocals) {
        super.visitMaxs(maxStack + 4, maxLocals)
    }
}

接着看看 LogisticsCenter.register() 方法,这个是 ARouter 里的源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// LogisticsCenter
private static void register(String className) {
    if (!TextUtils.isEmpty(className)) {
        try {
            Class<?> clazz = Class.forName(className);
            Object obj = clazz.getConstructor().newInstance();
            if (obj instanceof IRouteRoot) {
                registerRouteRoot((IRouteRoot) obj);
            } else if (obj instanceof IProviderGroup) {
                registerProvider((IProviderGroup) obj);
            } else if (obj instanceof IInterceptorGroup) {
                registerInterceptor((IInterceptorGroup) obj);
            } else {
                logger.info(TAG, "register failed, class name: " + className
                        + " should implements one of IRouteRoot/IProviderGroup/IInterceptorGroup.");
            }
        } catch (Exception e) {
            logger.error(TAG,"register class error:" + className);
        }
    }
}

分情况,根据实现接口 IRouteRootIProviderGroupIInterceptorGroup 注册对应的路由表,到此就路由表就注册完毕了。

一句话就是将运行时扫描 dex 注册路由表的工作提前到了编译期来做

下面是插入的代码:

4vpvg

loadRouterMap 插入了什么代码?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//源码代码,插桩前
private static void loadRouterMap() {
	//registerByPlugin一直被置为false
    registerByPlugin = false;
}
//插桩后反编译代码
private static void loadRouterMap() {
    registerByPlugin = false;
    register("com.alibaba.android.arouter.routes.ARouter$$Root$$modulejava");
    register("com.alibaba.android.arouter.routes.ARouter$$Root$$modulekotlin");
    register("com.alibaba.android.arouter.routes.ARouter$$Root$$arouterapi");
    register("com.alibaba.android.arouter.routes.ARouter$$Interceptors$$modulejava");
    register("com.alibaba.android.arouter.routes.ARouter$$Providers$$modulejava");
    register("com.alibaba.android.arouter.routes.ARouter$$Providers$$modulekotlin");
    register("com.alibaba.android.arouter.routes.ARouter$$Providers$$arouterapi");
}
本文由作者按照 CC BY 4.0 进行授权