ARouter源码解析(三)-- Provider和Interceptor源码分析


往期文章

  1. ARouter源码解析(一)-- 初始化分析
  2. ARouter源码解析(二)-- 路由跳转流程分析

Provider

在ARouter中Provider充当着服务(实现功能)的角色。比如框架字段的服务AutowiredServiceInterceptorServiceImpl等等。又或者可以自己定义一些服务类,来实现某些功能,比如PathReplaceService框架中预留的处理Path的服务类。在了解这些服务和运行原理前,先看一下IProvider基类

IProvider

/**
 * Provider interface, base of other interface.
 *
 * @author Alex <a href="mailto:zhilong.liu@aliyun.com">Contact me.</a>
 * @version 1.0
 * @since 16/8/23 23:08
 */
public interface IProvider {

    /**
     * Do your init work in this method, it well be call when processor has been load.
     *
     * @param context ctx
     */
    void init(Context context);
}
  • 接口很简单,就定义了一个方法init()通过注释可以看到,在这个方法中可以做一些初始化的操作
  • 通过as的快捷键ctrl+h,可以看到对应的继承类。
    在这里插入图片描述
    下面就来分析其中几个比较常用的服务类。

AutowiredService

AutowiredServiceImplAutowiredService的实现类

@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.
                    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.
        }
    }
}
  • 注解@Route可以看出这个服务可以通过路由的方式获取。详细的获取流程可以看之前写的路由流程篇。
  • init()中初始化了两个参数,classCacheblackList
    • classCache的作用是缓存类对象。它的类型LruCache得知,会把最近最少使用到的类删除。缓存的最大个数是66.
    • blackList应该就是一个黑名单,这里面的类都不会被初始化。
  • autowire()方法就是这个服务类所要显示的功能了。
    • 首先根据参数instance对象获取到对应的类名。
    • 判断这个类名是否在黑名单中
    • 如果不在中黑名单中就从classCache中获取。
    • 如果没在classCache中,就通过反射的方式实例化instance对应类名+$$Autowired所对应的类对象。
    • 可以看出实例化的类其父类都是ISyringe
    • 之后调用ISyringe.inject()方法
    • 最后把实例化的类存放到classCache中(减少反射次数,减少性能消耗)。

ISyringe

来看一下ISyringe中干了点啥。

/**
 * Template of syringe
 *
 * @author zhilong <a href="mailto:zhilong.lzl@alibaba-inc.com">Contact me.</a>
 * @version 1.0
 * @since 2017/2/20 下午4:41
 */
public interface ISyringe {
    void inject(Object target);
}
  • 是一个接口,就一个inject方法。接下来看一个实现类中做了什么操作。
/**
 * DO NOT EDIT THIS FILE!!! IT WAS GENERATED BY AROUTER. */
public class Test2Activity$$ARouter$$Autowired implements ISyringe {
  private SerializationService serializationService;

  @Override
  public void inject(Object target) {
    serializationService = ARouter.getInstance().navigation(SerializationService.class);
    Test2Activity substitute = (Test2Activity)target;
    substitute.key1 = substitute.getIntent().getExtras() == null ? substitute.key1 : substitute.getIntent().getExtras().getString("key1", substitute.key1);
  }
}
  • 看到这里,应该很清楚了,这就是@Autowried注解最终帮我们赋值的地方。
  • @Autowried注解帮我们生成的类也就是在这里。

回过头来,那是什么地方调用了AutowiredServiceImpl.autowire呢?

  • 查看调用链发现,就是在需要依赖注入的类中,调用ARouter.getInstance().inject(this)这句话完成了我们的传参赋值。

看完AutowiredServicelmpl的解析应该大概能清楚ARouterProvider的运作原理了。接下来我们看Interceptor在是如何运行的。

Interceptor

InterceptorServiceImpl

InterceptorServiceImpl是ARouter中管理拦截器的服务类。说明一下所有的自定义拦截器都需要继承自IInterceptor,而IInterceptor的父类就是IProvider。可见拦截器不过是一种特殊的服务类而已。

doInterceptions

该方法在路由流程篇中讲到过。大概在讲一下。
_ARouter.navigation()中被调用。

 if (!postcard.isGreenChannel()) {   // It must be run in async thread, maybe interceptor cost too mush time made ANR.
            interceptorService.doInterceptions(postcard, new InterceptorCallback() {
            ....
            }
            ....
}

可见每次路由操作都会走到拦截器逻辑中(除了设置了走绿色通道的操作)。

先看init()方法。

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;

                    logger.info(TAG, "ARouter interceptors init over.");

                    synchronized (interceptorInitLock) {
                        interceptorInitLock.notifyAll();
                    }
                }
            }
        });
    }
  • 这个方法是用来初始化项目中所有的拦截器类。
  • 跟服务和路由不同,拦截器类是一次性加载完的,不会按需加载。
  • 由于可能涉及到很多拦截器的加载,所以拦截器的初始化实在线程池中完成的。
  • 首先迭代Warehouse.interceptorsIndex集合。该集合的添加元素的流程可以看路由初始化篇文章。
  • 初始化完成的拦截器都添加到Warehouse.interceptors集合中
  • 拦截器逻辑在LogisticsCenter.executor中执行。所以拦截器逻辑是在异步线程中执行的。
  • 通过CancelableCountDownLatch interceptorCounter = new CancelableCountDownLatch(Warehouse.interceptors.size());方法,增加了对拦截器操作的超时处理。
  • 通过调用await来设置等待超时时间。当超过postcard中设置的超时时间之后会主动唤起阻塞的线程,执行接下来的逻辑。
_excute
  • iInterceptor.process是拦截器执行逻辑的方法。
  • onContinue表示拦截逻辑初始完成,多线程计数器会减1,之后调用迭代_excute调用下一个拦截器。
  • 调用onInterrupt表示路由请求被拦截,这个时候多线程计数器会清零,
  • _excute就完成了所有拦截器的调用逻辑。

到这里整个流程就梳理完了,接下来针对几个我自己在梳理的过程中想到的几点问题,另外解答一下。

拦截器是如何保证优先级的?

  • 回头来看init方法,先是对Warehouse.interceptorsIndex迭代的创建拦截器实例对象,添加到Warehouse.interceptors集合中。
  • doInterceptions中也只是按照顺序遍历执行拦截器,这么看好像没有看到跟拦截器优先级有关的信息啊。
  • 其实在我们自定义拦截器的时候都需要设置一个注解@Interceptor(priority = ),就是这个注解定义好了拦截器的优先级。
public class ARouter$$Interceptors$$app implements IInterceptorGroup {
  @Override
  public void loadInto(Map<Integer, Class<? extends IInterceptor>> interceptors) {
    interceptors.put(7, Test1Interceptor.class);
    interceptors.put(8, Test1Interceptor2.class);
  }
}
  • 这个类就是注解@Interceptor生成的文件(在介绍ARouter的自定义注解处理器篇会讲到生成逻辑)。
  • loadInto方法,其中interceptors就是Warehouse.interceptorsIndex集合。
  • 看到这里大家应该明白了,在ARouter注解处理器中,会根据拦截器类标注的注解@Interceptor(priority = )中设置的等级进行一个排序。等级越高的就排在越前面(1等级最大),这就是拦截器实现优先级功能的原理了。

到此本章的内容已经全部讲解完了,下一篇博客会将ARouter中自定义注解部分的内容。感兴趣的话可以加我的关注及时收到更新通知哈。

对于文中有疑惑的地方,或者有任何意见和建议的地方都可以评论留言,我会第一时间回复~与君共勉。

上一篇:ARouter源码解析(二)-- 路由跳转流程分析
下一篇:ARouter源码解析(四)-- arouter-compiler模块分析(APT流程)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值