前言
RxJava可能有些小伙伴没有听过是什么东西,可能是因为大家平时在做业务需求的时候对异步编程了解得比较少,而RxJava就是这么一个响应式编程框架,RxJava在安卓上面用得非常多,做安卓的朋友肯定对它很熟悉。那我这里为什么要讲这个呢?因为spring cloud中服务治理框架Hystrix中大量用到了RxJava的响应式编程,为了便于理解,这里也简单给大家介绍一下。这里介绍的版本是RxJava 1.X版本的, 而在去年的早些时候,官方便宣布,将在一段时间后不再对 RxJava 1.x 进行维护,推出了RxJava2.X版本,既然有新的,为什么不介绍新的呢?因为目前最新的Hystrix版本1.5.12中使用的RxJava是1.2版本的,而2.X版本的api改动还是比较大的,所以为了大家能更加简单的理解Hystrix,所以这里是对1.X版本的介绍。
响应式编程是什么
响应式编程是一种基于异步数据流概念的编程模式,有点类似于JAVA里面的lambda表达式,相信大家都很熟悉lambda吧。数据流,stream,大家肯定不陌生,我们可以对stream有很多操作,filter、map、reduce 等常见操作。然后响应式中的核心就是响应二字,响应什么呢?响应的是事件,event 。 而流就是一个按照时间进行排序的事件序列。RxJava里面的事件是基于观察者模式,事件流将从上往下,从订阅源传递到观察者。
RxJava中重要概念
RxJava 有四个基本概念:Observable
(可观察者,即被观察者)、 Observer
(观察者)、 Subscriber
(订阅,是Observer
的抽象实现类,本质上使用是一样的)、事件。Observable
和 Observer
通过 subscribe()
方法实现订阅关系,从而 Observable
可以在需要的时候发出事件来通知 Observer
。Observable
就像是一个生产者,在不断的生产消息,而Subscriber
和 Observer
就像是一个消费者,在不断的消费消息
另外, RxJava 的事件回调方法还定义了两个特殊的事件,在Hystrix中用得也非常多:onCompleted()
和 onError()
。
onCompleted()
: 事件队列完结。RxJava 不仅把每个事件单独处理,还会把它们看做一个队列。RxJava 规定,当不会再有新的 onNext()
发出时,需要触发 onCompleted()
方法作为标志。
onError()
: 事件队列异常。在事件处理过程中出异常时,onError()
会被触发,同时队列自动终止,不允许再有事件发出。
怎么做
说了这么多概念,估计大家都是一头雾水,我们直接来些实际的,加深大家的印象理解。用多的自然而然就会了,就懂了,这里说得可能不是最全的,但是说的都是Hystrix中用得很多的一些操作符,加深大家对Hystrix的理解,看源码就会容易一些。
例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| Observable<String> producer = Observable.create(new Observable.OnSubscribe<String>() { @Override public void call(Subscriber<? super String> subscriber) { subscriber.onNext("apple"); subscriber.onNext("orange"); subscriber.onCompleted(); } }); Subscriber<String> consumer = new Subscriber<String>() { @Override public void onNext(String s) { LOG.info("我收到的水果有 = {}" , s); } @Override public void onCompleted() { } @Override public void onError(Throwable e) { } }; producer.subscribe(consumer);
|
先来一个简单的例子给大家直观的介绍下Observable
和 Subscriber
做了些什么,Observable
使用了onNext方法生产了2个水果,Apple和orange ,然后调用了onCompleted方法结束了这次生产, 消费者用onnext方法收到了2个水果,所以消费者就将收到的水果打印出来了,没有做任何处理
执行结果如下:
1 2
| 2018-04-27 10:21:11.440 INFO [#][#] <main> com.dzy.learn.other.NormalTest :我收到的水果有 = apple 2018-04-27 10:21:11.440 INFO [#][#] <main> com.dzy.learn.other.NormalTest :我收到的水果有 = orange
|
然后再给大家介绍一下Hystrix中用得非常多的操作符
create
1 2 3 4 5 6 7 8 9
| Observable.create(new Observable.OnSubscribe<String>() { @Override public void call(Subscriber<? super String> subscriber) { subscriber.onNext("item1"); subscriber.onNext("item2"); subscriber.onCompleted(); } });
|
from
1 2 3 4 5 6 7
| List<String> fruitList = Arrays.asList("apple","orange"); Observable.from(fruitList).subscribe(new Action1<String>() { @Override public void call(String fruit) { LOG.info("fruit = {}" , fruit); } });
|
上面订阅者的代码被我简化了,直接new 一个Action1, 是subscribe支持的一种订阅方式,跟Subscriber是一样的道理,只是更加简化。然后我们再用lambda表达式简化一下就是这样的了
1 2
| List<String> fruitList = Arrays.asList("apple","orange"); Observable.from(fruitList).subscribe(fruit -> LOG.info("fruit = {}" , fruit));
|
执行结果如下:
1 2
| 2018-04-27 10:30:59.030 INFO [#][#] <main> com.dzy.learn.other.NormalTest :fruid = apple 2018-04-27 10:30:59.030 INFO [#][#] <main> com.dzy.learn.other.NormalTest :fruid = orange
|
defer
只有当订阅者订阅才创建Observable,为每个订阅创建一个新的Observable。内部通过OnSubscribeDefer
在订阅时调用Func0创建Observable
1 2 3 4 5 6 7 8 9 10 11 12
| List<String> fruitList = Arrays.asList("apple","orange"); Observable.defer(new Func0<Observable<String>>() { @Override public Observable<String> call() { return Observable.from(fruitList); } }).subscribe(new Action1<String>() { @Override public void call(String fruit) { LOG.info("defer fruit = {}" , fruit); } });
|
不知道大家理解了没有,每次生产消息都会生产一个新的消息生产者
执行结果如下:
1 2
| 2018-04-27 10:37:26.209 INFO [#][#] <main> com.dzy.learn.other.NormalTest :defer fruit = apple 2018-04-27 10:37:26.209 INFO [#][#] <main> com.dzy.learn.other.NormalTest :defer fruit = orange
|
startWith
在生产的第一个消息前加上一个或者一些消息,看例子比较直观
1 2 3 4
| List<String> fruitList = Arrays.asList("apple","orange"); Observable.from(fruitList) .startWith("before apple","before apple2") .subscribe(fruit->LOG.info("fruit = {}" , fruit));
|
执行结果如下:
1 2 3 4
| 2018-04-27 10:40:52.221 INFO [#][#] <main> com.dzy.learn.other.NormalTest :fruit = before apple 2018-04-27 10:40:52.221 INFO [#][#] <main> com.dzy.learn.other.NormalTest :fruit = before apple2 2018-04-27 10:40:52.222 INFO [#][#] <main> com.dzy.learn.other.NormalTest :fruit = apple 2018-04-27 10:40:52.222 INFO [#][#] <main> com.dzy.learn.other.NormalTest :fruit = orange
|
Filter
跟lambda里面的filter很像,也是用来筛选数据的,filter接收的Func1第二个参数是Boolean,定死的
1 2 3 4 5 6 7 8 9
| List<Integer> list = Arrays.asList(10, 5, 3, 2, 1, 0); Observable.from(list) .filter(new Func1<Integer, Boolean>() { @Override public Boolean call(Integer integer) { return integer>4; } }) .subscribe(num->LOG.info("比4大的num = {}" , num));
|
Map
Map是将需要生产的数据经过Func1进行变换之后,然后在发送给消费者。第二个参数是Object类型的,可以转化成一个Object对象
1 2 3 4 5 6 7 8 9
| List<Integer> list = Arrays.asList(10, 5, 3, 2, 1, 0); Observable.from(list) .map(new Func1<Integer, Object>() { @Override public Object call(Integer integer) { return integer+"变成str"; } }) .subscribe(s -> LOG.info("s = {}" , s));
|
输出如下:
1 2 3 4 5 6
| 2018-04-27 11:08:02.743 INFO [#][#] <main> com.dzy.learn.other.NormalTest :s = 10变成str 2018-04-27 11:08:02.747 INFO [#][#] <main> com.dzy.learn.other.NormalTest :s = 5变成str 2018-04-27 11:08:02.747 INFO [#][#] <main> com.dzy.learn.other.NormalTest :s = 3变成str 2018-04-27 11:08:02.748 INFO [#][#] <main> com.dzy.learn.other.NormalTest :s = 2变成str 2018-04-27 11:08:02.748 INFO [#][#] <main> com.dzy.learn.other.NormalTest :s = 1变成str 2018-04-27 11:08:02.748 INFO [#][#] <main> com.dzy.learn.other.NormalTest :s = 0变成str
|
FlatMap
跟map有些类似,但是也有很大的区别,map是一个对象变成另外一个对象,而flatMap可以把一个对象转化为多个对象 , 其实FlatMap是将一个对象转成了一个Observable
对象,转完之后,最开始的生产者并不发送这个 Observable
, 而是将它激活,于是它开始发送事件,每一个创建出来的 Observable
发送的事件,都被汇入同一个 Observable
,而这个 Observable
负责将这些事件统一交给 Subscriber
的回调方法,这样也就产生了一对多的概念,就像是把对象铺平了一样,flat
我会跟lambda的flatMap做一个对比,还是很像的
1 2 3 4 5 6 7 8 9 10
| List<Integer> list = Arrays.asList(10, 5, 3, 2, 1, 0); List<Object> flatMapcollect = list.stream().flatMap(new Function<Integer, Stream<?>>() { @Override public Stream<?> apply(Integer integer) { List<Integer> list1 = Arrays.asList(integer, integer + 10, integer + 100, integer + 1000); return list1.stream(); } }).collect(Collectors.toList()); flatMapcollect.forEach(s->LOG.info("complex integer = {}" , s));
|
打印的结果是一开始的每个元素10 ,5等都被加上了10 100 1000 然后输出了,相当于平铺了
1 2 3 4 5 6 7 8 9
| 2018-04-27 11:50:21.186 INFO [#][#] <main> com.dzy.learn.other.NormalTest :complex integer = 10 2018-04-27 11:50:21.191 INFO [#][#] <main> com.dzy.learn.other.NormalTest :complex integer = 20 2018-04-27 11:50:21.191 INFO [#][#] <main> com.dzy.learn.other.NormalTest :complex integer = 110 2018-04-27 11:50:21.191 INFO [#][#] <main> com.dzy.learn.other.NormalTest :complex integer = 1010 2018-04-27 11:50:21.191 INFO [#][#] <main> com.dzy.learn.other.NormalTest :complex integer = 5 2018-04-27 11:50:21.191 INFO [#][#] <main> com.dzy.learn.other.NormalTest :complex integer = 15 2018-04-27 11:50:21.191 INFO [#][#] <main> com.dzy.learn.other.NormalTest :complex integer = 105 2018-04-27 11:50:21.191 INFO [#][#] <main> com.dzy.learn.other.NormalTest :complex integer = 1005
|
RxJava里面的flatMap, 我乘以10,乘以100然后加下|
转成一个String
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| List<Integer> list = Arrays.asList(10, 5, 3, 2, 1, 0); Observable.from(list).flatMap(new Func1<Integer, Observable<?>>() { @Override public Observable<?> call(Integer num) { List<String> strings = Arrays.asList("|" + num + "|", "|" + num * 10 + "|", "|" + num * 100 + "|"); return Observable.from(strings); } }).subscribe(new Action1<Object>() { @Override public void call(Object o) { LOG.info("新转化后的字符串是 = {}" , o); } });
|
输出如下:
1 2 3 4 5 6 7 8 9
| 2018-04-27 11:57:13.316 INFO [#][#] <main> com.dzy.learn.other.NormalTest :新转化后的字符串是 = |10| 2018-04-27 11:57:13.320 INFO [#][#] <main> com.dzy.learn.other.NormalTest :新转化后的字符串是 = |100| 2018-04-27 11:57:13.320 INFO [#][#] <main> com.dzy.learn.other.NormalTest :新转化后的字符串是 = |1000| 2018-04-27 11:57:13.320 INFO [#][#] <main> com.dzy.learn.other.NormalTest :新转化后的字符串是 = |5| 2018-04-27 11:57:13.320 INFO [#][#] <main> com.dzy.learn.other.NormalTest :新转化后的字符串是 = |50| 2018-04-27 11:57:13.320 INFO [#][#] <main> com.dzy.learn.other.NormalTest :新转化后的字符串是 = |500| 2018-04-27 11:57:13.320 INFO [#][#] <main> com.dzy.learn.other.NormalTest :新转化后的字符串是 = |3| 2018-04-27 11:57:13.321 INFO [#][#] <main> com.dzy.learn.other.NormalTest :新转化后的字符串是 = |30| 2018-04-27 11:57:13.321 INFO [#][#] <main> com.dzy.learn.other.NormalTest :新转化后的字符串是 = |300|
|
reduce
reduce是一个聚合函数,接收上次运算的结果,放在下次的参数中,然后输出最后的结果,结果只输出一次。有点类似于递归。跟scan操作符很像,但是有区别,大家看下scan的输出就知道是什么区别了。
RxJava里面的reduce
1 2 3 4 5 6 7 8 9 10 11 12 13
| Observable.from(list).reduce(new Func2<Integer, Integer, Integer>() { @Override public Integer call(Integer result, Integer num) { LOG.info("开始前: result {}, num = {}" , result,num); result+=num; return result; } }).subscribe(new Action1<Integer>() { @Override public void call(Integer result) { LOG.info("result = {}" , result); } });
|
打印结果如下:
1 2 3 4 5 6
| 2018-04-27 13:47:29.237 INFO [#][#] <main> com.dzy.learn.other.NormalTest :开始前: result 10, num = 5 2018-04-27 13:47:29.241 INFO [#][#] <main> com.dzy.learn.other.NormalTest :开始前: result 15, num = 3 2018-04-27 13:47:29.241 INFO [#][#] <main> com.dzy.learn.other.NormalTest :开始前: result 18, num = 2 2018-04-27 13:47:29.241 INFO [#][#] <main> com.dzy.learn.other.NormalTest :开始前: result 20, num = 1 2018-04-27 13:47:29.241 INFO [#][#] <main> com.dzy.learn.other.NormalTest :开始前: result 21, num = 0 2018-04-27 13:47:29.241 INFO [#][#] <main> com.dzy.learn.other.NormalTest :result = 21
|
lambda里面的reduce
1 2 3 4 5 6 7 8
| List<Integer> list = Arrays.asList(10, 5, 3, 2, 1, 0); Integer sum = list.stream().reduce((result, sum1) -> { result += sum1; return result; }).get(); LOG.info("sum = {}" , sum);
|
scan
scan和reduce都是把上一次操作的结果做为第二次的参数传递给第二次Observable使用,但是scan每次操作之后先把数据输出,然后在调用scan的回调函数进行第二次操作,看例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| Observable.from(list) .scan(new Func2<Integer, Integer, Integer>() { @Override public Integer call(Integer result, Integer num) { LOG.info("开始前: result {}, num = {}" , result,num); result+=num; return result; } }).subscribe(new Action1<Integer>() { @Override public void call(Integer result) { LOG.info("result = {}" , result); } });
|
1 2 3 4 5 6 7 8 9 10 11
| 2018-04-27 13:47:29.245 INFO [#][#] <main> com.dzy.learn.other.NormalTest :result = 10 2018-04-27 13:47:29.245 INFO [#][#] <main> com.dzy.learn.other.NormalTest :开始前: result 10, num = 5 2018-04-27 13:47:29.245 INFO [#][#] <main> com.dzy.learn.other.NormalTest :result = 15 2018-04-27 13:47:29.245 INFO [#][#] <main> com.dzy.learn.other.NormalTest :开始前: result 15, num = 3 2018-04-27 13:47:29.245 INFO [#][#] <main> com.dzy.learn.other.NormalTest :result = 18 2018-04-27 13:47:29.245 INFO [#][#] <main> com.dzy.learn.other.NormalTest :开始前: result 18, num = 2 2018-04-27 13:47:29.245 INFO [#][#] <main> com.dzy.learn.other.NormalTest :result = 20 2018-04-27 13:47:29.245 INFO [#][#] <main> com.dzy.learn.other.NormalTest :开始前: result 20, num = 1 2018-04-27 13:47:29.245 INFO [#][#] <main> com.dzy.learn.other.NormalTest :result = 21 2018-04-27 13:47:29.245 INFO [#][#] <main> com.dzy.learn.other.NormalTest :开始前: result 21, num = 0 2018-04-27 13:47:29.245 INFO [#][#] <main> com.dzy.learn.other.NormalTest :result = 21
|
每次运算后都会调用订阅者
window
Hystrix 滑动窗口的核心用的就是window操作符,那么window有什么作用呢?他能将Observable的数据分拆成一些Observable窗口,然后把Observable窗口推送给订阅者,而不是一个数据,是一个Observable。来点例子更加直白
window(int count, int skip)
1 2 3 4 5 6 7 8 9 10 11 12
| List<Integer> list = Arrays.asList(10, 5, 3, 2, 1, 0); Observable.from(list).window(2, 2).subscribe(new Action1<Observable<Integer>>() { @Override public void call(Observable<Integer> integerObservable) { integerObservable.reduce((sum, num) -> sum+=num).subscribe(new Action1<Integer>() { @Override public void call(Integer integer) { LOG.info("我被2个打印一次 = {}" , integer); } }); } });
|
window里面有2个参数,第一个参数2 表示 选取2个事件,比如说10,5 5,3 等,第二个参数是skip,表示跳跃2个事件,来选取,所以是3组窗口,里面是 (10,5)(3,2)(1,0)
输出:
1 2 3
| 2018-04-27 14:06:08.703 INFO [#][#] <main> com.dzy.learn.other.NormalTest :我被2个打印一次 = 15 2018-04-27 14:06:08.707 INFO [#][#] <main> com.dzy.learn.other.NormalTest :我被2个打印一次 = 5 2018-04-27 14:06:08.707 INFO [#][#] <main> com.dzy.learn.other.NormalTest :我被2个打印一次 = 1
|
window(long timespan, TimeUnit unit)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| CountDownLatch countDownLatch = new CountDownLatch(1); Observable inputEventStream = Observable.create(new Observable.OnSubscribe<Object>() { @Override public void call(Subscriber<? super Object> subscriber) { subscriber.onNext("我是生产者........."); } }); inputEventStream.window(1000,TimeUnit.MILLISECONDS).subscribe(new Action1() { @Override public void call(Object o) { Calendar calendar = Calendar.getInstance(); int i = calendar.get(Calendar.SECOND); LOG.info("我会{}就被唤醒触发...",i); } }); countDownLatch.await();
|
输出:
1 2 3 4 5 6 7 8 9 10 11
| 2018-04-27 14:26:18.721 INFO [#][#] <RxComputationScheduler-1> com.dzy.learn.other.NormalTest :我会18就被唤醒触发... 2018-04-27 14:26:19.722 INFO [#][#] <RxComputationScheduler-1> com.dzy.learn.other.NormalTest :我会19就被唤醒触发... 2018-04-27 14:26:20.721 INFO [#][#] <RxComputationScheduler-1> com.dzy.learn.other.NormalTest :我会20就被唤醒触发... 2018-04-27 14:26:21.721 INFO [#][#] <RxComputationScheduler-1> com.dzy.learn.other.NormalTest :我会21就被唤醒触发... 2018-04-27 14:26:22.722 INFO [#][#] <RxComputationScheduler-1> com.dzy.learn.other.NormalTest :我会22就被唤醒触发... 2018-04-27 14:26:23.721 INFO [#][#] <RxComputationScheduler-1> com.dzy.learn.other.NormalTest :我会23就被唤醒触发... 2018-04-27 14:26:24.721 INFO [#][#] <RxComputationScheduler-1> com.dzy.learn.other.NormalTest :我会24就被唤醒触发... 2018-04-27 14:26:25.721 INFO [#][#] <RxComputationScheduler-1> com.dzy.learn.other.NormalTest :我会25就被唤醒触发... ..... ... ..
|
这里用CountDownLatch 阻塞了主线程的关闭,如果不用锁,那么主线程关闭了之后,你就看不到定时输出了。
第二个demo,用到了window另外的一个函数,第一个参数是缓存在这个window的间隔时间,第二个参数是时间单位 , 1s内收到的所有的生产消息都会缓存到window里面,然后统一发出给订阅者。就好像一个时间轴上面,有个窗子在收集数据,1s钟之后收集好了之后,就发送出去,然后到了第二个窗子,这就是Hystrix滑动窗口的精髓所在。
学以致用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| * 两个数字相加,reduce,scan用 */ public static final Func2<Integer, Integer, Integer> PUBLIC_SUM = (integer, integer2) -> integer + integer2; public static final Func1<Observable<Integer>, Observable<Integer>> WINDOW_SUM = window -> window.scan(0, PUBLIC_SUM).skip(1); public static final Func1<Observable<Integer>, Observable<Integer>> INNER_BUCKET_SUM = integerObservable -> integerObservable.reduce(0, PUBLIC_SUM); @Test public void testWindowSlide() throws InterruptedException { CountDownLatch countDownLatch = new CountDownLatch(1); BehaviorSubject<Integer> behaviorSubject = BehaviorSubject.create(); behaviorSubject .window(1000, TimeUnit.MILLISECONDS) .flatMap(INNER_BUCKET_SUM) .window(2,1) .flatMap(WINDOW_SUM) .subscribe((Integer integer) -> LOG.info("[{}] call ...... {}", Thread.currentThread().getName(), integer)); for (int i = 0; i < 1000; i++) { behaviorSubject.onNext(i); LOG.info("i = {}" ,i); Thread.sleep(200); } countDownLatch.await(); }
|
输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| 2018-04-27 15:46:06.547 INFO [#][#] <main> com.dzy.learn.other.NormalTest :i = 0 2018-04-27 15:46:06.756 INFO [#][#] <main> com.dzy.learn.other.NormalTest :i = 1 2018-04-27 15:46:07.010 INFO [#][#] <main> com.dzy.learn.other.NormalTest :i = 2 2018-04-27 15:46:07.211 INFO [#][#] <main> com.dzy.learn.other.NormalTest :i = 3 2018-04-27 15:46:07.411 INFO [#][#] <main> com.dzy.learn.other.NormalTest :i = 4 2018-04-27 15:46:07.517 INFO [#][#] <RxComputationScheduler-1> com.dzy.learn.other.NormalTest :[RxComputationScheduler-1] call ...... 10 2018-04-27 15:46:07.517 INFO [#][#] <RxComputationScheduler-1> com.dzy.learn.other.NormalTest :[RxComputationScheduler-1] call ...... 10 2018-04-27 15:46:07.611 INFO [#][#] <main> com.dzy.learn.other.NormalTest :i = 5 2018-04-27 15:46:07.811 INFO [#][#] <main> com.dzy.learn.other.NormalTest :i = 6 2018-04-27 15:46:08.011 INFO [#][#] <main> com.dzy.learn.other.NormalTest :i = 7 2018-04-27 15:46:08.211 INFO [#][#] <main> com.dzy.learn.other.NormalTest :i = 8 2018-04-27 15:46:08.411 INFO [#][#] <main> com.dzy.learn.other.NormalTest :i = 9 2018-04-27 15:46:08.517 INFO [#][#] <RxComputationScheduler-1> com.dzy.learn.other.NormalTest :[RxComputationScheduler-1] call ...... 45 2018-04-27 15:46:08.517 INFO [#][#] <RxComputationScheduler-1> com.dzy.learn.other.NormalTest :[RxComputationScheduler-1] call ...... 35 2018-04-27 15:46:08.611 INFO [#][#] <main> com.dzy.learn.other.NormalTest :i = 10 2018-04-27 15:46:08.811 INFO [#][#] <main> com.dzy.learn.other.NormalTest :i = 11 2018-04-27 15:46:09.011 INFO [#][#] <main> com.dzy.learn.other.NormalTest :i = 12 2018-04-27 15:46:09.211 INFO [#][#] <main> com.dzy.learn.other.NormalTest :i = 13 2018-04-27 15:46:09.411 INFO [#][#] <main> com.dzy.learn.other.NormalTest :i = 14 2018-04-27 15:46:09.517 INFO [#][#] <RxComputationScheduler-1> com.dzy.learn.other.NormalTest :[RxComputationScheduler-1] call ...... 95 2018-04-27 15:46:09.517 INFO [#][#] <RxComputationScheduler-1> com.dzy.learn.other.NormalTest :[RxComputationScheduler-1] call ...... 60
|
解析,第一个window产生了一个滑动窗口,每秒钟就会把生产者生产的消息累加起来,第二个window是积累2个对象,然后进行发送,每次跳一个数字,第二个window是建立在第一个windows累加之后的基础上的,可能有点难理解,我们来看第一个window产生的序列如下:
有的同学可能会问,你怎么知道,我看的log日志,打印出来的序列是 10 10 、 45 35 、95 60 、 145 85 、因为这里用的scan,每次累加之后都会把源数打印一遍,所以是0 10 35 60 85 。第二个window就在这个基础上进行累加 0+10 10+35 35+60 60+85,这样就完成了一个滑动窗口的监控过程
结语
这里总结的也许不是最全的,也许不是最新的版本,但是是Hystrix中用到的,结合Hystrix进行针对性讲解,对Hystrix的理解更加深刻,如有错误,望加以斧正,谢谢。