背景
在实际业务中,交易都是由多个上游组成的,一般成功的数据组织能够满足我们设计的要求,但是如果其中某个环节出了异常,在最终的下游很难捕获到哪里出了错误,尤其是需要在异常中添加一些业务信息与埋点功能相合作,完成线上问题排查,特此通过研究retryWhen操作符号源码,通代理模式,将异常进行统一封装处理,已满足这个场景的要求。
异常源码
// 封装一个业务需要的异常类,采用静态代理(装饰模式)扩展原异常
class BizThrowableExt(cause: Throwable?): Throwable(cause) {
// 业务相关数据,也可以通过继承,组合等模式形成复杂的业务属性
var url:String = ""
var code:String = ""
var msg:String = ""
}
异常处理源码
异常处理源码,实现Function,在内部通过flatMap操作,对上游传递下来的异常进行封装处理,最后通过 Observable.error 将异常再往下游传递。
import io.reactivex.Observable
import io.reactivex.ObservableSource
import io.reactivex.functions.Function
class ThrowableTransform<R>(private val url:String, private var code:String="", private var msg:String=""):Function<Observable<Throwable>,ObservableSource<R>> {
override fun apply(attempts: Observable<Throwable>): ObservableSource<R> {
return attempts.flatMap {
Observable.error(transform(it,url, code, msg))
}
}
private fun transform(original:Throwable, url:String, code:String, msg:String):Throwable{
return BizThrowableExt(original).apply {
this.url = url
this.msg = msg
this.code = code
}
}
}
业务源码
业务源码通模式登录和获取token 相关业务,在发生异常时,将业务相关信息,传递到下游,下游可以根据异常,获取到业务信息,和原始的异常。
private fun test2(){
Observable.zip(observableLogin(),observableToken()) { userInfo, token ->
println(" userInfo== $userInfo,token == $token")
userInfo + token
}.observeOn(AndroidSchedulers.mainThread())
.subscribe ({
println("${Thread.currentThread().id} resutl == $it")
},{
if(it is BizThrowableExt){
println("url == ${it.url}")
}
})
}
// 模拟登录相关业务
private fun observableLogin(): Observable<String?> {
return Observable.create(ObservableOnSubscribe<String?> { e: ObservableEmitter<String?> ->
println("observableLogin thread id ${Thread.currentThread().id}")
Thread.sleep(3000)
e.onNext("user login")
e.onError(RuntimeException())
e.onComplete()
}).subscribeOn(Schedulers.io())
.retryWhen(ThrowableTransform<String>("loginUrl","登录相关错误","登录相关信息"))
}
private fun observableToken(): Observable<String?> {
val data1 = "发起token其他信息"
return Observable.create(ObservableOnSubscribe<String?> { e: ObservableEmitter<String?> ->
try{
println("observableToken thread id ${Thread.currentThread().id}")
Thread.sleep(5000)
e.onNext("user token")
e.onComplete()
}catch (e:Exception){
//throw e
}
}).subscribeOn(Schedulers.io())
.retryWhen(ThrowableTransform<String>("tokeUrl","token相关错误",data1))
}
实现原理
名称定义:
- 通过代码Observable.create 创建的 Observable 称为 原上游 Observable
- retryWhen 内部创建的 Observable 称为异常处理上游
- 通过 subscribe 创建的Observer称为原下游
调用源码
Observable.create { e: ObservableEmitter<String?> ->
e.onNext("A")
e.onComplete()
}.retryWhen { attempts->
var count = 0;
attempts.flatMap { throwable ->
if(count < 3){
Observable.just("just retry!")
}else{
Observable.error(throwable)
}
}
}.subscribe {
println("result $it")
}
调用入口
public final Observable<T> retryWhen(
final Function<? super Observable<Throwable>, ? extends ObservableSource<?>> handler) {
ObjectHelper.requireNonNull(handler, "handler is null");
// 将retryWhen的上游(例子中是用Observable.create 创建出的上游)和 处理异常构建的上游 通过 ObservableRetryWhen 返回一个新的上游,带异常处理的上游
// 可以简单的认为 在参数1 中 添加了一个参数2 的功能
return RxJavaPlugins.onAssembly(new ObservableRetryWhen<T>(this, handler));
}
实现原理即rertyWhen源码
public final class ObservableRetryWhen<T> extends AbstractObservableWithUpstream<T, T>{
final Function<? super Observable<Throwable>, ? extends ObservableSource<?>> handler;
public ObservableRetryWhen(ObservableSource<T> source, Function<? super Observable<Throwable>, ? extends ObservableSource<?>> handler) {
// 保存原上游
super(source);
this.handler = handler;
}
@Override
protected void subscribeActual(Observer<? super T> observer) {
// 构建一个新的Subject ,接受订阅后的异常
Subject<Throwable> signaller = PublishSubject.<Throwable>create().toSerialized();
ObservableSource<?> other;
try {
other = ObjectHelper.requireNonNull(handler.apply(signaller), "The handler returned a null ObservableSource");
} catch (Throwable ex) {
Exceptions.throwIfFatal(ex);
EmptyDisposable.error(ex, observer);
return;
}
// 将上游和下游,和异常处理器封装起来
// 注意 RepeatWhenObserver 也是 Observer
// RepeatWhenObserver 在 订阅关系发生时,是先调用到RepeatWhenObserver
// RepeatWhenObserver 根据接受到的数据,在合适的机会给下游传递
RepeatWhenObserver<T> parent = new RepeatWhenObserver<T>(observer, signaller, source);
observer.onSubscribe(parent);
// other(内部有signaller) 和 parent.inner 形成订阅关系
other.subscribe(parent.inner);
// 将原上游和RepeatWhenObserver 形成订阅关系
parent.subscribeNext();
}
}
RepeatWhenObserver 源码如下
static final class RepeatWhenObserver<T> extends AtomicInteger implements Observer<T>, Disposable {
private static final long serialVersionUID = 802743776666017014L;
final Observer<? super T> downstream;
final AtomicInteger wip;
final AtomicThrowable error;
final Subject<Throwable> signaller;
final InnerRepeatObserver inner;
final AtomicReference<Disposable> upstream;
final ObservableSource<T> source;
volatile boolean active;
RepeatWhenObserver(Observer<? super T> actual, Subject<Throwable> signaller, ObservableSource<T> source) {
this.downstream = actual;
this.signaller = signaller;
this.source = source;
this.wip = new AtomicInteger();
this.error = new AtomicThrowable();
this.inner = new InnerRepeatObserver();
this.upstream = new AtomicReference<Disposable>();
}
@Override
public void onSubscribe(Disposable d) {
// 将原下游替换为 RepeatWhenObserver
DisposableHelper.replace(this.upstream, d);
}
@Override
public void onNext(T t) {
// 调用原下游继续传递onNext事件
HalfSerializer.onNext(downstream, t, this, error);
}
@Override
public void onError(Throwable e) {
DisposableHelper.replace(upstream, null);
active = false;
// 通过 signaller 转到 inner 中处理,将throwable 事件转换为 onNext事件
signaller.onNext(e);
}
@Override
public void onComplete() {
// 取消相关处理,包括 inner
DisposableHelper.dispose(inner);
// 调用原下游downstream 的onComplete
HalfSerializer.onComplete(downstream, this, error);
}
@Override
public boolean isDisposed() {
return DisposableHelper.isDisposed(upstream.get());
}
@Override
public void dispose() {
DisposableHelper.dispose(upstream);
DisposableHelper.dispose(inner);
}
void innerNext() {
// 重新将原上游和 RepeatWhenObserver 形成订阅关系
subscribeNext();
}
void innerError(Throwable ex) {
DisposableHelper.dispose(upstream);
// 直接调用原上游的onError
HalfSerializer.onError(downstream, ex, this, error);
}
void innerComplete() {
DisposableHelper.dispose(upstream);
HalfSerializer.onComplete(downstream, this, error);
}
void subscribeNext() {
if (wip.getAndIncrement() == 0) {
do {
if (isDisposed()) {
return;
}
if (!active) {
active = true;
source.subscribe(this);
}
} while (wip.decrementAndGet() != 0);
}
}
// 当原上游 出现异常时候,在 InnerRepeatObserver 处理
final class InnerRepeatObserver extends AtomicReference<Disposable> implements Observer<Object> {
private static final long serialVersionUID = 3254781284376480842L;
@Override
public void onSubscribe(Disposable d) {
DisposableHelper.setOnce(this, d);
}
@Override
public void onNext(Object t) {
innerNext();
}
@Override
public void onError(Throwable e) {
innerError(e);
}
@Override
public void onComplete() {
innerComplete();
}
}
}
总结
- retryWhen 是将 原下游封装为RepeatWhenObserver
- 当上游数据订阅时,替换为 RepeatWhenObserver的dispose
- 原上游 onNext onComplete 通过 RepeatWhenObserver 调用原下游的onNext onComplete
- 将retryWhen 入参 ,和 RepeatWhenObserver 的 InnerRepeatObserver 形成订阅关系
- 在原上游 发生onError时,调用到 retryWhen 的入参构建的上游
- 在 retryWhen 的入参构建的上游 调用onNext 是,通过subscribeNext(); 将订阅关系重置,当调用onError 时,直接向下游传递 onError。
- 根据第6点,文章对原上游的异常进行封装不会更改原数据的传递,并且可以将封装后的异常传递到下游。