1、spring cloud bus
spring cloud是按照spring的配置對一系列微服務框架的集成,spring cloud bus是其中一個微服務框架,用於實現微服務之間的通信。
spring cloud bus整合 java的事件處理機制和消息中間件消息的發送和接受,主要由發送端、接收端和事件組成。針對不同的業務需求,可以設置不同的事件,發送端發送事件,接收端接受相應的事件,並進行相應的處理。
2、spring cloud bus實戰
網上關於spring cloud bus的demo相當多,此處就不贅述了。
3、原理
spring cloud bus整合了java的事件處理機制和消息中間件,所以下面就從這兩個方面來說明spring cloud bus的原理。
如圖所示,作如下解釋:
(1)完整流程:發送端(endpoint)構造事件event,將其publish到context上下文中(spring cloud bus有一個父上下文,bootstrap),然后將事件發送到channel中(json串message),接收端從channel中獲取到message,將message轉為事件event(轉換過程這一塊沒有深究),然后將event事件publish到context上下文中,最后接收端(Listener)收到event,調用服務進行處理。整個流程中,只有發送/接收端從context上下文中取事件和發送事件是需要我們在代碼中明確寫出來的,其它部分都由框架封裝完成。
(2)先大致描述了一下流程,關於封裝的部分流程,我們基本上可以在BusAutoConfiguration.class中找到,下面的代碼都是這個類中的代碼
@EventListener(classes = RemoteApplicationEvent.class) public void acceptLocal(RemoteApplicationEvent event) { if (this.serviceMatcher.isFromSelf(event) && !(event instanceof AckRemoteApplicationEvent)) { this.cloudBusOutboundChannel.send(MessageBuilder.withPayload(event).build()); } }
這是封裝了java事件處理機制,當收到RemoteApplicationEvent時,如果這個event是從這個服務發出的,而且不是ack事件,那么就會把這個事件發送到channel中。
@StreamListener(SpringCloudBusClient.INPUT) public void acceptRemote(RemoteApplicationEvent event) { if (event instanceof AckRemoteApplicationEvent) { if (this.bus.getTrace().isEnabled() && !this.serviceMatcher.isFromSelf(event) && this.applicationEventPublisher != null) { this.applicationEventPublisher.publishEvent(event); } // If it's an ACK we are finished processing at this point return; } if (this.serviceMatcher.isForSelf(event) && this.applicationEventPublisher != null) { if (!this.serviceMatcher.isFromSelf(event)) { this.applicationEventPublisher.publishEvent(event); } if (this.bus.getAck().isEnabled()) { AckRemoteApplicationEvent ack = new AckRemoteApplicationEvent(this, this.serviceMatcher.getServiceId(), this.bus.getAck().getDestinationService(), event.getDestinationService(), event.getId(), event.getClass()); this.cloudBusOutboundChannel .send(MessageBuilder.withPayload(ack).build()); this.applicationEventPublisher.publishEvent(ack); } } if (this.bus.getTrace().isEnabled() && this.applicationEventPublisher != null) { // We are set to register sent events so publish it for local consumption, // irrespective of the origin this.applicationEventPublisher.publishEvent(new SentApplicationEvent(this, event.getOriginService(), event.getDestinationService(), event.getId(), event.getClass())); } }
@StreamListener這個標簽有興趣的可以去了解一下。這個方法就是從channel中取出事件進行處理的過程(message轉事件部分需要自行了解,我沒有深入研究),根據事件的類型、發送方和接收方來處理這個事件:如果是ack事件,發送到context上下文中;如果自己是接收端且不是發送端,就會將事件發送到context上下文。
(3)消息中間件可以采用rabbitmq、kafka之類的
(4)說兩個比較有意思的問題
1)自定義事件時,我們需要添加無參構造方法:目的在於,在message轉事件時,會調用這個無參構造方法,具體情況可以去參考源碼看看
2)自定義事件時,事件的參數需要用final修飾,這個一直沒有找到合理的解釋,有興趣可以去研究研究