RxJava之六——RxBus 通过RxJava来替换EventBus

转载请标明出处:http://blog.csdn.net/xx326664162/article/details/53736241 文章出自:薛瑄的博客

关于RxJava,从表面上看起来很容易使用,但是如果理解不够深刻,使用过程中,往往会出现一些问题,所以我写了五篇文章,从入门到精通,从简单的使用到部分源码详解,希望能给读者一个质的飞跃:
1、RxJava之一——一次性学会使用RxJava RxJava简单的使用和使用它的好处
2、RxJava之二——Single和Subject 与Observable举足轻重的类,虽然用的少,但应该知道
3、RxJava之三——RxJava 2.0 全部操作符示例
4、RxJava之四—— Lift()详解 想要了解Operators,Lift()一定要学习
5、RxJava之五—— observeOn()与subscribeOn()的详解Scheduler线程切换的原理
6、RxJava之六——RxBus 通过RxJava来替换EventBus

RxBus并不是一个库,而是一种模式。相信大多数开发者都使用过EventBus,作为事件总线通信库,如果你的项目已经加入RxJava和EventBus,不妨用RxBus代替EventBus,以减少库的依赖。

懂得Android的开发者都知道,目前Android上最火的两个Event Bus库是Otto和Green Robot’sEventBus,两个事件总线库写的都非常不错。不过这里不是讲事件总线,而是讲如何通过RxJava来实现事件总线的效果。

实现RxBus的思路:

1、首先创建一个可同时充当Observer和Observable的Subject;

2、创建事件类,不同的事件使用不同的类

3、注册事件:在需要接收事件的地方,订阅该Subject(此时Subject是作为Observable),在这之后,一旦Subject接收到事件,立即发射给该订阅者;

4、发送事件:将事件post至Subject,此时Subject作为Observer接收到事件(onNext),然后会发射给所有订阅该Subject的订阅者。

示例

总体来说,代码非常的简单

1、定义RxBus类

/**
* RxBus
* Created by YoKeyword on 2015/6/17.
*/
public class RxBus {
    private static volatile RxBus defaultInstance;

    private final Subject<Object, Object> bus;
    // PublishSubject只会把在订阅发生的时间点之后来自原始Observable的数据发射给观察者
    public RxBus() {
      bus = new SerializedSubject<>(PublishSubject.create());
    }
    // 单例RxBus
    public static RxBus getDefault() {
        if (defaultInstance == null) {
            synchronized (RxBus.class) {
                if (defaultInstance == null) {
                    defaultInstance = new RxBus();
                }
            }
        }
        return defaultInstance ;
    }
    // 发送一个新的事件
    public void post (Object o) {
        bus.onNext(o);
    }
    // 根据传递的 eventType 类型返回特定类型(eventType)的 被观察者
    public <T> Observable<T> toObservable (Class<T> eventType) {

           // ofType = filter + cast
           return bus.ofType(eventType);
    }
}

注:
1、Subject同时充当了Observer和Observable的角色,Subject是非线程安全的,要避免该问题,需要将 Subject转换为一个 SerializedSubject ,上述RxBus类中把线程非安全的PublishSubject包装成线程安全的Subject。

2、PublishSubject只会把在订阅发生的时间点之后来自原始Observable的数据发射给观察者。

3、ofType操作符只发射指定类型的数据,其内部就是filter+cast

2 、定义事件

userEvent是要发送的事件,如果你用过EventBus, 很容易理解,UserEvent的代码:

public class UserEvent {
    long id;
    String name;
    public UserEvent(long id,String name) {
        this.id= id;
        this.name= name;
    }
    public long getId() {
        return id;
    }
    public String getName() {
        return name;
    }
}

3、接收事件的代码:

// rxSubscription是一个Subscription的全局变量,这段代码可以在onCreate/onStart等生命周期内
rxSubscription = RxBus.getDefault().toObserverable(UserEvent.class)
        .subscribe(new Action1<UserEvent>() {
               @Override
               public void call(UserEvent userEvent) {
                   long id = userEvent.getId();
                   String name = userEvent.getName();
                   ...
               }
           },
        new Action1<Throwable>() {
            @Override
            public void call(Throwable throwable) {
                // TODO: 处理异常
            }        
        });

4、发送事件的代码:

RxBus.getDefault().post(new UserEvent (1, "yoyo"));

5、取消订阅事件

最后一定要记得在生命周期结束的地方取消订阅事件,防止RxJava可能会引起的内存泄漏问题。

@Override
protected void onDestroy() {
    super.onDestroy();
    if(!rxSubscription.isUnsubscribed()) {
        rxSubscription.unsubscribe();
    }
}

这样,一个简单的Event Bus就实现了!如果你的项目已经开始使用RxJava,建议可以把Otto和Green Robot’sEventBus去掉了,直接使用RxBus!!

参考:
用RxJava实现事件总线(Event Bus)
RxBus—通过RxJava来替换EventBus
RxBus的实现及简单使用

关注我的公众号,轻松了解和学习更多技术
这里写图片描述

发布了244 篇原创文章 · 获赞 799 · 访问量 234万+
展开阅读全文

springcloud:访问/bus/refresh地址后出现错误,,client端出现以下错误

04-03

springcloud config-server rabbitmq 配置自动刷新,在访问/bus/refresh地址后,client端出现以下错误 ## **client-config** org.springframework.amqp.rabbit.listener.exception.ListenerExecutionFailedException: Listener threw exception at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.wrapToListenerExecutionFailedExceptionIfNeeded(AbstractMessageListenerContainer.java:1506) ~[spring-rabbit-2.0.2.RELEASE.jar:2.0.2.RELEASE] at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:1417) ~[spring-rabbit-2.0.2.RELEASE.jar:2.0.2.RELEASE] at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.actualInvokeListener(AbstractMessageListenerContainer.java:1337) ~[spring-rabbit-2.0.2.RELEASE.jar:2.0.2.RELEASE] at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:1324) ~[spring-rabbit-2.0.2.RELEASE.jar:2.0.2.RELEASE] at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.executeListener(AbstractMessageListenerContainer.java:1303) ~[spring-rabbit-2.0.2.RELEASE.jar:2.0.2.RELEASE] at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.doReceiveAndExecute(SimpleMessageListenerContainer.java:785) [spring-rabbit-2.0.2.RELEASE.jar:2.0.2.RELEASE] at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.receiveAndExecute(SimpleMessageListenerContainer.java:769) [spring-rabbit-2.0.2.RELEASE.jar:2.0.2.RELEASE] at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$700(SimpleMessageListenerContainer.java:77) [spring-rabbit-2.0.2.RELEASE.jar:2.0.2.RELEASE] at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.run(SimpleMessageListenerContainer.java:1010) [spring-rabbit-2.0.2.RELEASE.jar:2.0.2.RELEASE] at java.lang.Thread.run(Thread.java:745) [na:1.8.0_111] Caused by: org.springframework.messaging.converter.MessageConversionException: Cannot convert from [java.lang.String] to [org.springframework.cloud.bus.event.RemoteApplicationEvent] for GenericMessage [payload={"type":"RefreshRemoteApplicationEvent","timestamp":1522749739659,"originService":"config-server:8888","destinationService":"**","id":"202be12a-7597-45a9-8731-bb4454e4da4f"}, headers={amqp_receivedDeliveryMode=PERSISTENT, amqp_receivedExchange=springCloudBus, amqp_deliveryTag=1, deliveryAttempt=3, amqp_consumerQueue=springCloudBus.anonymous.9cLCAd4QRVCfurGMHUDmrg, X-B3-ParentSpanId=c5f8bad949d06b94, amqp_redelivered=false, messageSent=true, spanTraceId=5daa65f9b6124b03, spanId=3e738e68342e56ad, spanParentSpanId=c5f8bad949d06b94, amqp_receivedRoutingKey=springCloudBus, nativeHeaders={spanTraceId=[5daa65f9b6124b03], spanId=[3e738e68342e56ad], spanParentSpanId=[c5f8bad949d06b94], spanSampled=[0]}, X-B3-SpanId=3e738e68342e56ad, X-B3-Sampled=0, X-B3-TraceId=5daa65f9b6124b03, id=d01f292e-7a7f-dec5-c49b-50fc36e6b1b3, spanSampled=0, amqp_consumerTag=amq.ctag-HJJsrtYoTr5gc-g7fUQFkA, contentType=text/plain}] at org.springframework.messaging.handler.annotation.support.PayloadArgumentResolver.resolveArgument(PayloadArgumentResolver.java:144) ~[spring-messaging-5.0.4.RELEASE.jar:5.0.4.RELEASE] at org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:116) ~[spring-messaging-5.0.4.RELEASE.jar:5.0.4.RELEASE] at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:137) ~[spring-messaging-5.0.4.RELEASE.jar:5.0.4.RELEASE] at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:109) ~[spring-messaging-5.0.4.RELEASE.jar:5.0.4.RELEASE] at org.springframework.cloud.stream.binding.StreamListenerMessageHandler.handleRequestMessage(StreamListenerMessageHandler.java:55) ~[spring-cloud-stream-2.0.0.RC3.jar:2.0.0.RC3] at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal(AbstractReplyProducingMessageHandler.java:109) ~[spring-integration-core-5.0.3.RELEASE.jar:5.0.3.RELEASE] at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:164) ~[spring-integration-core-5.0.3.RELEASE.jar:5.0.3.RELEASE] at org.springframework.integration.dispatcher.AbstractDispatcher.tryOptimizedDispatch(AbstractDispatcher.java:116) ~[spring-integration-core-5.0.3.RELEASE.jar:5.0.3.RELEASE] at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:132) ~[spring-integration-core-5.0.3.RELEASE.jar:5.0.3.RELEASE] at org.springframework.integration.dispatcher.UnicastingDispatcher.dispatch(UnicastingDispatcher.java:105) ~[spring-integration-core-5.0.3.RELEASE.jar:5.0.3.RELEASE] at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:73) ~[spring-integration-core-5.0.3.RELEASE.jar:5.0.3.RELEASE] at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:463) ~[spring-integration-core-5.0.3.RELEASE.jar:5.0.3.RELEASE] at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:407) ~[spring-integration-core-5.0.3.RELEASE.jar:5.0.3.RELEASE] at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:181) ~[spring-messaging-5.0.4.RELEASE.jar:5.0.4.RELEASE] at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:160) ~[spring-messaging-5.0.4.RELEASE.jar:5.0.4.RELEASE] at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:47) ~[spring-messaging-5.0.4.RELEASE.jar:5.0.4.RELEASE] at org.springframework.messaging.core.AbstractMessageSendingTemplate.send(AbstractMessageSendingTemplate.java:108) ~[spring-messaging-5.0.4.RELEASE.jar:5.0.4.RELEASE] at org.springframework.integration.endpoint.MessageProducerSupport.sendMessage(MessageProducerSupport.java:203) ~[spring-integration-core-5.0.3.RELEASE.jar:5.0.3.RELEASE] at org.springframework.integration.amqp.inbound.AmqpInboundChannelAdapter.access$1100(AmqpInboundChannelAdapter.java:59) ~[spring-integration-amqp-5.0.3.RELEASE.jar:5.0.3.RELEASE] at org.springframework.integration.amqp.inbound.AmqpInboundChannelAdapter$Listener.lambda$onMessage$0(AmqpInboundChannelAdapter.java:217) ~[spring-integration-amqp-5.0.3.RELEASE.jar:5.0.3.RELEASE] at org.springframework.retry.support.RetryTemplate.doExecute(RetryTemplate.java:287) ~[spring-retry-1.2.2.RELEASE.jar:na] at org.springframework.retry.support.RetryTemplate.execute(RetryTemplate.java:180) ~[spring-retry-1.2.2.RELEASE.jar:na] at org.springframework.integration.amqp.inbound.AmqpInboundChannelAdapter$Listener.onMessage(AmqpInboundChannelAdapter.java:214) ~[spring-integration-amqp-5.0.3.RELEASE.jar:5.0.3.RELEASE] at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:1414) ~[spring-rabbit-2.0.2.RELEASE.jar:2.0.2.RELEASE] ... 8 common frames omitted 2018-04-03 18:02:22.789 WARN [user-service,,,] 9428 --- [VCfurGMHUDmrg-1] ingErrorHandler$DefaultExceptionStrategy : Fatal message conversion error; message rejected; it will be dropped or routed to a dead letter exchange, if so configured: (Body:'{"type":"RefreshRemoteApplicationEvent","timestamp":1522749739659,"originService":"config-server:8888","destinationService":"**","id":"202be12a-7597-45a9-8731-bb4454e4da4f"}' MessageProperties [headers={spanTraceId=5daa65f9b6124b03, spanId=8e507c0a47a5fd86, nativeHeaders={spanTraceId=[5daa65f9b6124b03], spanId=[3e738e68342e56ad], spanParentSpanId=[c5f8bad949d06b94], spanSampled=[0]}, messageSent=true, spanSampled=0, contentType=text/plain, originalContentType=application/json;charset=UTF-8}, contentType=text/plain, contentLength=0, receivedDeliveryMode=PERSISTENT, priority=0, redelivered=false, receivedExchange=springCloudBus, receivedRoutingKey=springCloudBus, deliveryTag=1, consumerTag=amq.ctag-HJJsrtYoTr5gc-g7fUQFkA, consumerQueue=springCloudBus.anonymous.9cLCAd4QRVCfurGMHUDmrg]) 2018-04-03 18:02:25.803 WARN [user-service,,,] 9428 --- [VCfurGMHUDmrg-1] s.a.r.l.ConditionalRejectingErrorHandler : Execution of Rabbit message listener failed. ![图片说明](https://img-ask.csdn.net/upload/201804/03/1522751337_771358.png) ==================================已解决=================================== ==================================已解决=================================== ==================================已解决=================================== ==================================已解决=================================== Spring boot 2.0的改动较大,/bus/refresh全部整合到actuador里面了,所以之前1.x的management.security.enabled全部失效,不适用于2.0 适用于2.0的配置是这样的: ``` management: endpoints: web: exposure: include: bus-refresh ``` 另外注解 ``` @RefreshScope ``` 需要在配置的页面加上,就是说附带@Value的页面加上此注解 请求刷新的页面由原来1.5.x的localhost:8888/bus/refresh 变成:http://localhost:8888/actuator/bus-refresh 注意:config-server和config-client的配置都得加上 ``` management: endpoints: web: exposure: include: bus-refresh ``` 配置 整合被折腾了好几天,实在是大坑 问答

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 代码科技 设计师: Amelia_0503

分享到微信朋友圈

×

扫一扫,手机浏览