RxCache创建缓存接口的核心代码是下面这一段
mCacheProviders = new RxCache.Builder()
.persistence(cacheDirectory,new GsonSpeaker())
.using(CacheProviders.class);
创建RxCache的内部类Builder。这里可以选择通过创建的Builder的setMaxMBPersistenceCache设置缓存的容量,useExpiredDataIfLoaderNotAvailable设置是否使用过期缓存。调用persistence设置磁盘缓存的目录以及序列化的工具,在该方法的结尾会有这么一段代码,传入了之前创建的Builder作为参数来构造RxCache。
return new RxCache(this);
然后是调用RxCache的using方法,
public <T> T using(final Class<T> classProviders) {
proxyProviders = new ProxyProviders(builder, classProviders);
return (T) Proxy.newProxyInstance(
classProviders.getClassLoader(),
new Class<?>[] {classProviders},
proxyProviders);
}
这里使用到了动态代理。Proxy的newProxyInstance传入了所需代理的类的加载器,该类实现接口的数组,以及invocationHandler的实现类(ProxyProviders实现了InvocationHandler,重载了invoke方法),返回的代理对象可以同原对象一样调用自身方法,且invoke方法中可以对方法调用作额外的处理,相当于方法的拦截。
然后看一下ProxyProvider,首先是构造方法,用到了Dagger依赖注入,
public ProxyProviders(RxCache.Builder builder, Class<?> providersClass) {
processorProviders = DaggerRxCacheComponent.builder()
.rxCacheModule(new RxCacheModule(builder.getCacheDirectory(),
builder.useExpiredDataIfLoaderNotAvailable(),
builder.getMaxMBPersistenceCache(), getEncryptKey(providersClass),
getMigrations(providersClass), builder.getJolyglot()))
.build().providers();
proxyTranslator = new ProxyTranslator();
}
简单来说就是将processorProviders的创建独立出来。RxCacheModule构造函数中传入了许多需要注入的对象,比如从RxCache.builder中获取的参数(上文有提到),还有根据缓存接口的方法注解获取的参数。首先对象DaggerRxCacheComponent(需要编译),其中有这两个方法(因为对Dagger还不是太熟悉,才去看了一下内部实现方法。。):
@Override
public ProcessorProviders providers() {
return RxCacheModule_ProvideProcessorProvidersFactory.proxyProvideProcessorProviders(
rxCacheModule, getProcessorProvidersBehaviour());
}
...
private ProcessorProvidersBehaviour getProcessorProvidersBehaviour() {
return new ProcessorProvidersBehaviour(
twoLayersCacheProvider.get(),
useExpiredDataIfLoaderNotAvailableProvider.get(),
evictExpiredRecordsPersistenceProvider.get(),
getGetDeepCopy(),
getDoMigrations());
}
可以看出processorProvider的创建是在这里完成的,再看一下RxCacheModule,结合一下上文所说的。其实ProcessorProvider的构造函数中的参数,只要构成他们的基本元素(就是有@Providers注解的方法提供的)都有,就可以完成构造。顺便提一句,RxCache这个项目里基本上都是用Dagger在进行类的创建管理。
public RxCacheModule(File cacheDirectory, Boolean useExpiredDataIfLoaderNotAvailable,
Integer maxMgPersistenceCache,
String encryptKey, List<MigrationCache> migrations, JolyglotGenerics jolyglot) {
this.cacheDirectory = cacheDirectory;
this.useExpiredDataIfLoaderNotAvailable = useExpiredDataIfLoaderNotAvailable;
this.maxMgPersistenceCache = maxMgPersistenceCache;
this.encryptKey = encryptKey;
this.migrations = migrations;
this.jolyglot = jolyglot;
}
@Singleton @Provides File provideCacheDirectory() {
return cacheDirectory;
}
@Singleton @Provides Persistence providePersistence(io.rx_cache2.internal.Disk disk) {
return disk;
}
@Singleton @Provides Boolean useExpiredDataIfLoaderNotAvailable() {
return useExpiredDataIfLoaderNotAvailable;
}
@Singleton @Provides io.rx_cache2.internal.Memory provideMemory() {
return new ReferenceMapMemory();
}
@Singleton @Provides Integer maxMbPersistenceCache() {
return maxMgPersistenceCache != null ? maxMgPersistenceCache : 100;
}
@Singleton @Provides Encryptor provideEncryptor() {
return new BuiltInEncryptor();
}
@Singleton @Provides String provideEncryptKey() {
return encryptKey != null ? encryptKey : "";
}
@Singleton @Provides List<MigrationCache> provideMigrations() {
return migrations != null ? migrations : new ArrayList<MigrationCache>();
}
@Singleton @Provides JolyglotGenerics provideJolyglot() {
return jolyglot;
}
@Provides io.rx_cache2.internal.ProcessorProviders provideProcessorProviders(
io.rx_cache2.internal.ProcessorProvidersBehaviour processorProvidersBehaviour) {
return processorProvidersBehaviour;
}
}
上面讲到ProxyProvider这个实现了InvocationHandler的类可以重载invoke来对缓存接口方法进行拦截处理,并且在ProxyProvider自己的构造函数中用依赖注入生成了processorProviders对象。接下来看一下invoke方法:
@Override public Object invoke(final Object proxy, final Method method, final Object[] args)
throws Throwable {
return Observable.defer(new Callable<ObservableSource<?>>() {
@Override public ObservableSource<?> call() throws Exception {
Observable observable =
processorProviders.process(proxyTranslator.processMethod(method, args));
Class<?> methodType = method.getReturnType();
if (methodType == Observable.class) return Observable.just(observable);
if (methodType == Single.class) return Observable.just(Single.fromObservable(observable));
if (methodType == Maybe.class) {
return Observable.just(Maybe.fromSingle(Single.fromObservable(observable)));
}
if (method.getReturnType() == io.reactivex.Flowable.class) {
return Observable.just(observable.toFlowable(BackpressureStrategy.MISSING));
}
String errorMessage = method.getName() + io.rx_cache2.internal.Locale.INVALID_RETURN_TYPE;
throw new RuntimeException(errorMessage);
}
}).blockingFirst();
}
首先关注一下proxyTranslator.processMethod(method,args),这里传入的就是缓存接口的方法和方法带的参数。再看一下具体实现:
private final Map<Method, ConfigProvider> configProviderMethodCache;
...
ConfigProvider processMethod(Method method, Object[] objectsMethod) {
ConfigProvider prev = loadConfigProviderMethod(method);
ConfigProvider configProvider = new ConfigProvider(prev.getProviderKey(),
null, prev.getLifeTimeMillis(), prev.requiredDetailedResponse(), prev.isExpirable(),
prev.isEncrypted(), getDynamicKey(method, objectsMethod),
getDynamicKeyGroup(method, objectsMethod),
getLoaderObservable(method, objectsMethod),
evictProvider(method, objectsMethod));
return configProvider;
}
...
private ConfigProvider loadConfigProviderMethod(Method method) {
ConfigProvider result;
synchronized (configProviderMethodCache) {
result = configProviderMethodCache.get(method);
if (result == null) {
result = new ConfigProvider(getProviderKey(method),
null, getLifeTimeCache(method),
requiredDetailResponse(method), getExpirable(method), isEncrypted(method),
null, null, null, null);
configProviderMethodCache.put(method, result);
}
}
return result;
}
configProviderMethodCache是以method为键,ConfigProvider为值的HashMap,将接口方法和其对应的配置(方法注解,方法参数)保存起来。每次调用先在HashMap中找对应的ConfigProvider,如果找不到则新建一个,其中的构造函数最后四个参数都是null,然后将其存入HashMap,表明HashMap中存入的是不包含接口缓存方法参数的信息的。而这些信息在每次调用proxyTranslator.processMethod时,会进行获取。具体如何获取接口缓存的注解信息,参数信息不详细说了。可以看一下这篇文章:https://www.jianshu.com/p/5d73909c7068。
然后就是processorProviders.process,传入的是缓存接口方法的配置信息。所以关注到ProcessorProvidersBehaviour,在说它的process方法前,先看一下这个:
@Inject public ProcessorProvidersBehaviour(...) {
...
this.oProcesses = startProcesses(doMigrations, evictExpiredRecordsPersistence);
}
private Observable<Integer> startProcesses(
io.rx_cache2.internal.migration.DoMigrations doMigrations,
final io.rx_cache2.internal.cache.EvictExpiredRecordsPersistence evictExpiredRecordsPersistence) {
Observable<Integer> oProcesses = doMigrations.react().flatMap(new Function<Integer, ObservableSource<Integer>>() {
@Override public ObservableSource<Integer> apply(Integer ignore) throws Exception {
return evictExpiredRecordsPersistence.startEvictingExpiredRecords();
}
}).subscribeOn((Schedulers.io())).observeOn(Schedulers.io()).share();
oProcesses.subscribe(new Consumer<Integer>() {
@Override public void accept(Integer ignore) throws Exception {
hasProcessesEnded = true;
}
});
return oProcesses;
}
ProcessorProviderBehaviour在创建过程先进行了Migration(数据迁移),具体的可以看一下@SchedueMigration和@Migration注解的使用方法。聚焦到doMigrations.react(),doMigration也是依赖注入的,构造的参数是磁盘缓存(persistence),@Migration注解的集合(List<Migration>),解密的密钥(encryptKey)。
@Inject public DoMigrations(Persistence persistence, List<MigrationCache> migrations,
String encryptKey) {
this.getClassesToEvictFromMigrations = new GetClassesToEvictFromMigrations();
this.getCacheVersion = new io.rx_cache2.internal.migration.GetCacheVersion(persistence);
this.getPendingMigrations = new io.rx_cache2.internal.migration.GetPendingMigrations();
this.migrations = migrations;
this.upgradeCacheVersion = new io.rx_cache2.internal.migration.UpgradeCacheVersion(persistence);
this.deleteRecordMatchingClassName = new io.rx_cache2.internal.migration.DeleteRecordMatchingClassName(persistence, encryptKey);
}
上面创建的几个类,接下来会接着分析react方法一一讲清楚,
public Observable<Integer> react() {
return getCacheVersion.react()
.flatMap(new Function<Integer, ObservableSource<List<MigrationCache>>>() {
@Override public ObservableSource<List<MigrationCache>> apply(Integer currentCacheVersion)
throws Exception {
return getPendingMigrations.with(currentCacheVersion, migrations).react();
}
})
.flatMap(new Function<List<MigrationCache>, ObservableSource<List<Class>>>() {
@Override public ObservableSource<List<Class>> apply(List<MigrationCache> migrationCaches)
throws Exception {
return getClassesToEvictFromMigrations.with(migrationCaches).react();
}
}).flatMap(new Function<List<Class>, ObservableSource<Integer>>() {
@Override public ObservableSource<Integer> apply(List<Class> classes) throws Exception {
return deleteRecordMatchingClassName.with(classes).react();
}
})
.flatMap(new Function<Integer, ObservableSource<Integer>>() {
@Override public ObservableSource<Integer> apply(Integer ignore) throws Exception {
return upgradeCacheVersion.with(migrations).react();
}
});
}
这些都是调用RxJava中的flatMap操作符来表示整个迁移过程。首先是getCacheVersion.react(),
Observable<Integer> react() {
Integer currentVersion = persistence.retrieve(KEY_CACHE_VERSION, Integer.class, false, null);
currentVersion = currentVersion == null ? 0 : currentVersion;
return Observable.just(currentVersion);
}
意为获取当前的版本,这里的获取是通过persistence.retrieve,也就是读取缓存目录下KEY_CACHE_VERSION名字文件,取得一个版本号版本号,然后Observable.just发射版本号。
public Observable<List<io.rx_cache2.MigrationCache>> react() {
if (migrations == null || migrations.isEmpty()) {
return Observable.just((List<io.rx_cache2.MigrationCache>) new ArrayList<io.rx_cache2.MigrationCache>());
}
Collections.sort(migrations, new Comparator<io.rx_cache2.MigrationCache>() {
@Override public int compare(
io.rx_cache2.MigrationCache migration1, io.rx_cache2.MigrationCache migration2) {
return migration1.version() - migration2.version();
}
});
List<io.rx_cache2.MigrationCache> pendingMigrations = new ArrayList<>();
for (io.rx_cache2.MigrationCache migration : migrations) {
if (cacheVersion < migration.version()) {
pendingMigrations.add(migration);
}
}
return Observable.just(pendingMigrations);
}
getPendingMigrations.react()方法主要比较Migration集合的版本号和当前版本号,筛选出比当前版本新的Migration。其中对这个集合按照版本号进行排序,加快筛选速度。
Observable<List<Class>> react() {
List<Class> classesToEvict = new ArrayList<>();
for (io.rx_cache2.MigrationCache migration : migrations) {
for (Class candidate : migration.evictClasses()) {
if (!isAlreadyAdded(classesToEvict, candidate)) classesToEvict.add(candidate);
}
}
return Observable.just(classesToEvict);
}
getClassesToEvictFromMigration.react(),作用是从Migrations中获取要清理的类型。将取得的类型去重后存入List当中。
public Observable<Integer> react() {
if (classes.isEmpty()) return Observable.just(1);
List<String> allKeys = persistence.allKeys();
for (String key : allKeys) {
io.rx_cache2.internal.Record record = persistence.retrieveRecord(key, false, encryptKey);
if (record == null) {
record = persistence.retrieveRecord(key, true, encryptKey);
}
if (evictRecord(record)) {
persistence.evict(key);
}
}
return Observable.just(1);
}
deleteRecordMatchingClassName.react(),遍历磁盘缓存,匹配到类型相同的缓存进行清理。
Observable<Integer> react() {
if (migrations == null || migrations.isEmpty()) return Observable.just(1);
io.rx_cache2.MigrationCache migration = migrations.get(migrations.size() - 1);
persistence.save(KEY_CACHE_VERSION, migration.version(), false, null);
return Observable.just(1);
}
upgradeCacheVersion.react(),更新版本号,取的是集合中最后一个元素的版本号,因为之前排过序。
数据迁移主要的原因应该是同样的缓存接口,接受的类型有所变化,所以导致旧缓存无法使用,这时候就要根据旧缓存的旧类型进行缓存清理。
总结一下,这一章主要讲了部分RxCache的调用过程,包括,RxCache的builder用来设置参数,ProxyProviders如何作为接口缓存的代理对象,ProxyTranslator将接口缓存方法的参数和注解转换成ConfigProvider,processorProvider的依赖注入,还有数据迁移的具体实现。