文章目录
往期文章
Provider
在ARouter中Provider充当着服务(实现功能)的角色。比如框架字段的服务AutowiredService
、InterceptorServiceImpl
等等。又或者可以自己定义一些服务类,来实现某些功能,比如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
AutowiredServiceImpl
是AutowiredService
的实现类
@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()
中初始化了两个参数,classCache
和blackList
。- 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
的解析应该大概能清楚ARouter
中Provider
的运作原理了。接下来我们看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流程)