RxCache的简单源码分析

  1. RxCache本身的一些宏观机制和自己的构思还是比较契合的:
    • 最基本的一点,都将所有数据回调形式统一为Observable.
    • 复合key,tag + 附加信息的方式,但是RxCache做的更为复杂,还支持keyGroup的概念。
    • 数据提取模块化,每种数据提取方式都是独立的,并且是可扩展的,当然也是Obserable化的。
    • 对返回的数据进行包装从而得以返回更多元数据,比如source。
    • 都采取了disk + memory的缓存方案,但是我这边直接使用了DualCache,扩展性上是不如RxCache提供的Persistence接口的。
  2. 不一样的地方:

    • RxCache这种基于Proxy+注解进行扩展的方式要更加灵活一些,不过个人感觉如果是项目内部使用,让RxJava来维护数据提取模块也是可以接受的。
    • RxCache对于缓存过期的实现通过注解来实现,应该算是更加优雅,不过这样的话,过期时间其实是不可改变的了。
    • RxCache本身对数据的提取内部做了一个定死的优先级排列:先取缓存,缓存无效,才取真正提供的数据源,尽管提供了evict做强制的数据源提取,但是不是很灵活,但是在我们实际项目中,是有很多其他case色。
    • RxCache因为把数据源提取全部外放,可能导致对复数个数据源的case不能很好兼容。
  3. RxCache是一个基于RxJava的异步数据缓存库,其角色定位不是一个数据加载和缓存控制总管,而像一个service提供者和功能装饰者. 一句话总结: 我不生产数据,我只是数据的”搬运(二次处理+控制)”工。

  4. RxCache提供了using函数(这个设计比较有意思,RxCache本身更像一个Factory,通过using来生产出一个被处理过的DataProvider来给用户使用)来将数据提取的某些职责分离了出来(参数名中的Provider表明了 provide数据(即生成数据) 这一功能被从RxCache中分离,严格意义上讲,这种分离是必须的,让每个外部的数据提供者都能做适配)。
  5. RxCache的using函数接受一个Class对象(classProviders), 并且返回的是该Class一个被Proxy了的实例:

    1. 为了使用Java提供的Proxy机制,需要一个实现了InvocationHandler的实例,在这里这个实例的类型是ProxyProviders,其实例化需要的参数有RxCache构造使用的Builder和using函数参数的Class
    2. 然后基于上面构造的ProxyProviders实例,yongJava的Proxy机制返回一个所有函数调用会被拦截到ProxyProviders实例并实现了classProviders接口的对象
  6. 那么从上面看,RxCache**自己能做手脚的地方就在上面生成的InvocationHandler(ProxyProviders)实例了**:

    • 首先看ProxyProviders的关键函数invoke()(InvocationHandler所规定的接口,所有对被Proxy对象的函数调用都会被拦截到该接口上)
    • 该函数的实现是调用Observable.defer(Func0<Observable<T>> observableFactory)构造一个Observable,defer的作用是为每个subscribe了该Observable的observer根据函数中提供的工厂构造方法构造一个Observable.
    • 那么这里的工厂构造方法就是processorProviders.process(proxyTranslator.processMethod(method, args)
    • 上面的processorProviders是ProxyProviders对象构造时生成的一个ProcessorProviders对象。proxyTranslator同样也是构造时进行了实例化。
    • ProcessorProviders本身的定位是 Entry point for RxCache,其process函数可以根据提供的ConfigProvider信息返回一个Observable
    • 先关注ProxyTranslator:
      • 上面调用的是其processMethod(method, args)函数,method是被拦截的方法对应的Method对象,而args则是调用该函数时传递的一系列参数。
      • processMethod(Method method, Object[] objectsMethod)会根据输入的Method对象和函数参数生成一个ConfigProvider作为返回结果。
        • 首先调用loadConfigProviderMethod(method)来获取一个ConfigProvider(注意其名字是prev).
          • loadConfigProviderMethod(Method method)本质上是从ProxyTranslator内部的一个缓存(Map<Method, ConfigProvider>)中根据传入的Method对象查找是否之前已经有处理过的缓存结果(很多涉及到反射类分析的库都会这样做),如果有,那么直接返回(所以上面返回的才叫prev,因为不是最新的结果)
          • 否则,就构造一个ConfigProvider实例,构造的参数包括:
            1. getProviderKey(method): 返回方法的名称
            2. getLifeTimeCache(method): 如果方法上有LifeCache注解,那么返回其duration属性。
            3. requiredDetailResponse(method):判断方法返回值的类型(method.getReturnType())是否是Observable(不是则会抛异常,因为RxCache一个要求是外部提供的Provider接口的返回值类型都应该是Observable), 并且Observable的范型类型是否继承自Reply(RxCache自己规定的数据返回包装格式)
            4. getExpirable(method):方法上是否有Expirable注解表明其返回的数据会过期,如果是false,那么代表数据永远不会过期
            5. isEncrypted(method):方法上是否有Expirable注解,是否加密。
        • 然后利用该ConfigProvider的部分信息结合其他信息构造出一个configProvider作为返回结果. 使用了如下新的构造信息:
          1. dynamicKey -> getDynamicKey(method, objectsMethod), 基于method和此次调用的参数生成一个用于标记这种特殊(具体参数不一样,那么key当然应该不一样)请求的数据key
          2. dynamicKeyGroup -> getDynamicKeyGroup(method, objectsMethod), 基本同上,不过group范围更大,对应一批特定条件。
          3. loaderObservable -> getLoaderObservable(method, objectsMethod) 一个关键的对象,这个对象本身承载了真正的数据加载功能,并且是外部提供的,是数据的“源”,而RxCache只是对这个源做了二次处理,比如如果数据没过期那么显然不需要从“源”那里直接取,用RxCache自己本身缓存的数据即可
          4. EvictProvider -> evictProvider(method, objectsMethod)
        • 上面4个对象的取值都是基于getObjectFromMethodParam(Method method, Class expectedClass, Object[] objectsMethod)函数:
          • 该函数遍历Method被调用时输入的参数,如果有参数的类型满足expectedClass.isAssignableFrom(objectParam.getClass()),并且满足这种条件的参数只有一个(多余1个直接抛异常,因为破坏了RxCache的约定),那么就返回该参数对象。说白了就是根据实现约定好的参数类型,从被拦截方法的调用参数中找到和约定类型一致的对象
        • 那么其实上面4个对象本质上讲就是外部调用时传入的参数对象
        • 根据上面的分析,ConfigProvider里面封装的信息就是该方法本身的属性(名称,相关注解)以及方法的调用参数(只不过Proxy机制不能直接拿到各个类型对应的值,invoke传递参数时直接传一个Object数组,没有常规函数调用那样的类型对应,还需要遍历处理一遍)
    • 再回到ProxyProviders的defer的Observable构造函数中,现在可以知道proxyTranslator.processMethod(method, args)最终返回的是一个对本次方法调用的信息的集合体(既包括了方法本身的静态信息,也包括了本次调用参数的动态信息)
    • 然后processorProviders根据这部分信息返回一个真正给外部使用的Observable。
    • ProxyProviders的processorProviders本身实例化的过程比较复杂(涉及到依赖注入),其最终对应的实现类是ProcessorProvidersBehaviour,其process函数也是调用Observable的defer来为每个observer生成一个Observable。
      • process的核心调用是getData(final ConfigProvider configProvider):
        • 第一步使用twoLayersCache.retrieve(configProvider.getProviderKey(), configProvider.getDynamicKey()………..),本质就是基于此次调用的信息(都已经被提取被填充到了configProvider中)从twoLayersCache中提取出之前的缓存信息(如果有的话),缓存针对的粒度是方法本身+方法调用参数
        • 用Observable.just将得到的数据转化为一个Observable。
        • 后面紧接一个map operator,其转化路径是:<Record, Observable<Reply>>,从twoLayersCache.retrive返回的Record类型转化为Observable<Reply>
        • 如果发现从twoLayersCache中得到的数据是有效的,并且本次调用没有指定evict,那么表明缓存中的数据是直接可以用的, 直接将返回的Record封装为一个Replay通过just进行消息的续传
        • 如果发现缓存中没有数据或者数据不可用,那么调用getDataFromLoader(), 故名思意,使用外部调用者提供的loader(数据的源)来提取数据
        • getDataFromLoader()的调用主要包括: 调用提供的loader来取数据,取完数据以后保存到twoLayersCache中做缓存
        • 通过读缓存或者数据源最终返回数据(以Reply的包装形式)以后会再接一个flatMap <Observable<Reply>, Observable<Object>> 结合 getReturnType(configProvider, reply)函数将得到的数据做一次DeepCopy然后如果方法中要求了requiredDetailedResponse, 那么返回一个封装了Data的Reply(这里的Detail就好理解了,意思是除了Data本身,还返回一些元数据,包括数据的来源以及数据是否加密),如果没有要求返回详细信息,则直接返回数据本身。
        • 最终,呈现给外部使用者的,是一个Data或者封装了Data的Reply,并且都是通过Observable来完成数据回调的。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值