ARouter 学习- 源码分析如何做到控制反转

//分析如何跨模块调用API.
ARouter使用时,需要先调用下面方法做初始化操作:
ARouter.init(mApplication); // 尽可能早,推荐在Application中初始化
下面跟源码看看init到底做了哪些操作

test
上图是大概的一个调用时序,可以看到最终在LogisticsCenter做了大量的操作。那LogisticsCenter是什么呢?

Logistics Center,从名字上翻译就是物流中心,整个SDK的流转以及内部调用最终都会下沉到这一层,当然也会按照功能模块进行划分。
进入LogisticsCenter.init方法中看看:

 public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException {
        try {
            Set<String> routerMap;
                // These class was generate by arouter-compiler.
                routerMap = ClassUtils.getFileNameByPackageName(mContext, ROUTE_ROOT_PAKCAGE);
         
            for (String className : routerMap) {
                if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_ROOT)) {
                   // This one of root elements, load root.
                    ((IRouteRoot) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.groupsIndex);
                } else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_PROVIDERS)) {
                    // Load providerIndex
                    ((IProviderGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.providersIndex);
                }
            }
 
        } catch (Exception e) {
            throw new HandlerException(TAG + "ARouter init logistics center exception! [" + e.getMessage() + "]");
        }
    }
 
routerMap = ClassUtils.getFileNameByPackageName(mContext, ROUTE_ROOT_PAKCAGE);
调用ClassUtils.getFileNameByPakageName方法。扫描 com.alibaba.android.arouter.routes包下面包含的所有的ClassName。


将获取到的className集合保存到routerMap中。

 for (String className : routerMap) {
                if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_ROOT)) {
                   // This one of root elements, load root.
                    ((IRouteRoot) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.groupsIndex);
                } else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_PROVIDERS)) {
                    // Load providerIndex
                    ((IProviderGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.providersIndex);
                }
            }
遍历routerMap元素,通过className的检测执行相应class的loadInfo方法. 注意loadInfo的参数,传递的是WareHouse
/**
 * Storage of route meta and other data.
 *
 * @author zhilong <a href="mailto:zhilong.lzl@alibaba-inc.com">Contact me.</a>
 * @version 1.0
 * @since 2017/2/23 下午1:39
 */
class Warehouse {
    // 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<>();
WareHouse会缓存route,provider.
  public void loadInto(Map<String, RouteMeta> providers) {
    providers.put("com.router.service.IService", RouteMeta.build(RouteType.PROVIDER, MyService.class, "/service/hello", "service", null, -1, -2147483648));
  }
    
  public void loadInto(Map<String, Class<? extends IRouteGroup>> routes) {
    routes.put("service", ARouter\$\$Group\$\$service.class);
  }
LogisticsCenter.init分析完毕。
总结:ARouter.init最终是调用到的LogisticsCenter.init,将通过注解处理器生成的class加载出来,执行class的loadInfo方法,并将信息缓存到WareHouse中。

ARouter初始化完了,接下里看如何使用了。
((IService) ARouter.getInstance().build("/service/hello").navigation()).sayHello(this);
上面代码拆开看,先看ARouter.getInstance().build("/service/hello").
跟着源码,发现最终是调用的_ARouter.getInstance().build();
 /**
     * Build postcard by path and default group
     */
    protected Postcard build(String path) {
            PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);
            if (null != pService) {
                path = pService.forString(path);
            }
            return build(path, extractGroup(path));
    }
方法内结果又调用了ARouter.getInstance().navigation(),而navigation最终还是调用的_ARouter.getInstance().navigation()

   protected <T> T navigation(Class<? extends T> service) {
        try {
            Postcard postcard = LogisticsCenter.buildProvider(service.getName());

            // Compatible 1.0.5 compiler sdk.
            if (null == postcard) { // No service, or this service in old version.
                postcard = LogisticsCenter.buildProvider(service.getSimpleName());
           }
            LogisticsCenter.completion(postcard);
            return (T) postcard.getProvider();
        } catch (NoRouteFoundException ex) {
            logger.warning(Consts.TAG, ex.getMessage());
            return null;
        }
    }
调用LogisticsCenter.buildProvider
 public static Postcard buildProvider(String serviceName) {
        RouteMeta meta = Warehouse.providersIndex.get(serviceName);

        if (null == meta) {
            return null;
        } else {
            return new Postcard(meta.getPath(), meta.getGroup());
        }
    }
从WareHouse的providersIndex里根据PathReplaceService的className 查找RouterMeta。前面分析Init时,LogisticsCenter.init没有保存PathReplaceService的provider信息。执行各种return。
回到_ARouter.getInstance().build().因为
PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);
返回的是null,执行
build(path, extractGroup(path));
看看这个build做啥了
 protected Postcard build(String path, String group) {
            PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);
            if (null != pService) {
                path = pService.forString(path);
            }
            return new Postcard(path, group);
        }
    }
也是先调用navigation,获取到null,最终返回一个Postcard

/**
 * A container that contains the roadmap.
 *
 * @author Alex <a href="mailto:zhilong.liu@aliyun.com">Contact me.</a>
 * @version 1.1.0
 * @since 16/8/22 19:16
 */
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;
      A container that contains the roadmap. 
    小结: ARouter.getInstance().build("/service/hello")。最终获取到一个Postcard.
 
ARouter.getInstance().build("/service/hello").navigation()

     获取到Postcard后,会执行navigation方法。继续跟进
   Postcard.navigation最终是调用_ARouter.getInstance().navigation.
protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
                        .............
			LogisticsCenter.completion(postcard);
			.................
            return _navigation(context, postcard, requestCode, callback);

     
    }
先调用LogisticsCenter.completion方法:
 public synchronized static void completion(Postcard postcard) {
		RouteMeta routeMeta = Warehouse.routes.get(postcard.getPath());
		if(null==routeMeta)
				    Class<? extends IRouteGroup> groupMeta = Warehouse.groupsIndex.get(postcard.getGroup());  // Load route meta.
                    IRouteGroup iGroupInstance = groupMeta.getConstructor().newInstance();
                    iGroupInstance.loadInto(Warehouse.routes);
               
                completion(postcard);   // Reload
            }
        } else {
            postcard.setDestination(routeMeta.getDestination());
            postcard.setType(routeMeta.getType());
            postcard.setPriority(routeMeta.getPriority());
            postcard.setExtra(routeMeta.getExtra());


            switch (routeMeta.getType()) {
                case PROVIDER:  // if the route is provider, should find its instance
                    // Its provider, so it must be implememt 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;
       
                default:
                    break;
            }
        }
    }
 第一步先从
RouteMeta routeMeta = Warehouse.routes.get(postcard.getPath());
查询是不是包含需要的RouteMeta。在ARouter.init初始化时,因为资源和性能上的考虑并没有加载RouteMeta信息到Warehouse中,按需加载。因此此处routeMeta为null。
执行按需加载逻辑,从WareHouse.groupsIndex按照key 是service获取到group class.
routes.put("service", ARouter\$\$Group\$\$service.class);
然后执行ARouter\$\$Group\$\$service的loadInfo方法,传入参数为WareHouse.routes.
iGroupInstance.loadInto(Warehouse.routes)

loadInfo具体实现如下:

public void loadInto(Map<String, RouteMeta> atlas) {
    atlas.put("/service/hello", RouteMeta.build(RouteType.PROVIDER, MyService.class, "/service/hello", "service", null, -1, -2147483648));
  }
执行完loadInfo后,执行
 completion(postcard);   // Reload
又回到completion,这次从
RouteMeta routeMeta = Warehouse.routes.get(postcard.getPath());
读取到的routeMeta不为null了,执行else逻辑。
完善postcard信息:

postcard.setDestination(routeMeta.getDestination());
            postcard.setType(routeMeta.getType());
            postcard.setPriority(routeMeta.getPriority());
            postcard.setExtra(routeMeta.getExtra());
处理PROVIDER case:
    case PROVIDER:  // if the route is provider, should find its instance
                    // Its provider, so it must be implememt 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);
根据routeMeta获取到需求依赖的服务类,创建对象,并将对象保存在postcard中。

ARouter.getInstance().build("/service/hello").navigation()
执行上面方法最终会将创建的服务对象,返回给上层。上层拿到服务对象后,执行跨模块调用API。










  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值