clickhouse原理解析与开发实战 pdf_微服务架构开发实战:SpringCloudBus的设计原理

Spring Cloud Bus 设计原理

本节将介绍Spring Cloud Bus的设计原理。理解原理有利于更好地基于Spring Cloud Bus来进行二次开发。

536866390a52a36abdcec1918123b969.png

基于Spring Cloud Stream

Spring Cloud Bus是基于Spring Cloud Stream基础之上而做的封装。Spring Cloud Stream是Spring Cloud家族中一个构建消息驱动微服务的框架。

图16-3所示的是来自官方的Spring Cloud Stream应用模型。

a2ddfc482033d433fc7be541a9b970a3.png

在该应用模型中可以发现Spring Cloud Stream的几个核心概念。

1.Spring Cloud Stream Application

Application通过inputs或outputs来与SpringCloud Stream中的 Binder交互,通过配置来binding,而Spring Cloud Stream的 Binder负责与中间件交互。所以只需要搞清楚如何与Spring Cloud Stream交互就可以方便使用消息驱动的方式。

2.Binder

Binder是Spring Cloud Stream 的一个抽象概念,是应用与消息中间件之间的黏合剂。目前Spring Cloud Stream实现了Kafka和 Rabbit等消息中间件的 Binder。

通过Binder,可以很方便地连接消息中间件,可以动态地改变消息的destinations(对应于Kaf-ka 的 topic,Rabbit 的exchanges),这些都可以通过外部配置项做到。通过配置,不需要修改一行代码,就能实现消息中间件的更换。

3.订阅/发布

消息的发布(Publish)和订阅(Subscribe)是事件驱动的经典模式,如图16-4所示。SpringCloud Stream的数据交互也是基于这个思想。生产者把消息通过某个topic广播出去(Spring CloudStream 中的destinations)。其他的微服务通过订阅特定topic来获取广播出来的消息,以触发业务的进行。

607df865f627e313b8c63bacf5c2f969.png

这种模式极大地降低了生产者与消费者之间的耦合。即使有新的应用引入,也不需要破坏当前系统的整体结构。

4.消费者分组

Spring Cloud Stream的意思基本与Kafka一致。为了防止同一个事件被重复消费,只要把这些应用放置于同一个“group”中,就能够保证消息只会被其中一个应用消费一次。

每个binding 都可以使用spring.cloud.stream.bindings..group来指定分组的名称,如图16-5所示。

966732f40614bc8f84b38b69e1371ad5.png

图16-5展示了Stream 的消费者分组设置,属性值分别设置为spring.cloud.stream.bind-ings..group=hdfsWrite和 spring.cloud.stream.bindings..group=average.

5.持久化

消息事件的持久化是必不可少的。Spring Cloud Stream可以动态地选择一个消息队列是否需要持久化。

6.Binding

Binding 是通过配置把应用与Spring Cloud Stream的 Binder绑定在一起的,之后只需要修改Binding 的配置来达到动态修改topic、exchange、type等一系列信息,而不需要修改一行代码。

7.分区支持

Spring Cloud Stream支持在给定应用程序的多个实例之间对数据进行分区。在分区方案中,物理通信介质(如topic)被视为多个分区。

Spring Cloud Stream为统一实现分区处理用例提供了一个通用抽象。无论代理本身是自然分区(如Kafka)还是非自然分区(如RabbitMQ),都可以使用分区。

210ca3559962545d13117f9e731541a8.png

Spring Cloud Bus的编程模型

当微服务之间需要通信时,先将消息传递给消息总线,而其他微服务实现接收消息总线分发信息。Spring Cloud Bus提供了简化微服务发送和接收消息总线指令的能力。

1.AbstractBusEndpoint及其子类

通过这个接口来实现用户的访问,都需要继承AbstractBusEndpoint。

以下是AbstractBusEndpoint.java的核心代码。

package org.springframework.cloud.bus.endpoint;import org.springframework.boot.actuate.endpoint.Endpoint;import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoint;import org.springframework.context.ApplicationEvent;import org.springframework.context.ApplicationEventPublisher;public class AbstractBusEndpoint implements MvcEndpointprivate ApplicationEventPublisher context;private BusEndpoint delegate;private string appId;public AbstractBusEndpoint(ApplicationEventPublisher context,StringappId,BusEndpoint busEndpoint){this.context =context;this.apprd = appId;this.delegate = busEndpoint;}protected string getInstanceId() {return this.appld;protected void publish(ApplicationEvent event)context.publishEvent (event);}@overridepublic String getPath()return "/"+this.delegate.getld();}overridepublic boolean issensitive({return this.delegate.isSensitive(;}@override@Suppresswarnings("rawtypes")public Class<?extends Endpoint> getEndpointType()freturn this.delegate.getClass();}}

最常用的AbstractBusEndpoint 的子类,莫过于EnvironmentBusEndpoint和RefreshBusEndpoint。

这两个类分别实现了/bus/env和/bus/refresh的HTTP接口。

以下是 EnvironmentBusEndpoint.java的源码。

package org.springframework.cloud.bus.endpoint;import java.util.Map;import org.springframework.cloud.bus.event.EnvironmentChangeRemoteApplicationEvent;import org.springframework.context.ApplicationEventPublisher;import org.springframework.jmx.export.annotation.Managed0peration;import org.springframework.jmx.export.annotation.ManagedResource;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.bind.annotation.ResponseBody;@ManagedResourcepublic class EnvironmentBusEndpoint extends AbstractBusEndpoint {public EnvironmentBusEndpoint (ApplicationEventPublisher context,string id,BusEndpoint delegate) {super(context, id,delegate);}@RequestMapping(value = "env", method = RequestMethod.POST)@ResponseBodyManagedOperationpublic void env(@RequestParam Map params,@RequestParam(value = "destination",required = false)String destination){publish(new EnvironmentChangeRemoteApplicationEvent(this,getInstancerd(,destination,params));}}

以下是RefreshBusEndpoint.java的源码。

package org.springframework.cloud.bus.endpoint;import org.springframework.cloud.bus.event.RefreshRemoteApplicationEvent;import org.springframework.context.ApplicationEventPublisher;import org.springframework.jmx.export.annotation.Managed0peration;import org.springframework.jmx.export.annotation.ManagedResource;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.bind.annotation.ResponseBody;@ManagedResourcepublic class RefreshBusEndpoint extends AbstractBusEndpointpublic RefreshBusEndpoint (ApplicationEventPublisher context,Stringid,BusEndpoint delegate)fsuper(context, id, delegate);RequestMapping(value = "refresh",method = RequestMethod.POST)ResponseBody@Managedoperationpublic void refresh(@RequestParam(value = "destination", required = false)String destination){publish(new RefreshRemoteApplicationEvent(this, getInstanceId(),destination));}}

2.RemoteApplicationEvent及其子类

RemoteApplicationEvent用来定义被传输的消息事件。

以下是RemoteApplicationEvent.java的源码。

package org.springframework.cloud.bus.event;import java.util.UUID;import org.springframework.context.ApplicationEvent;import org.springframework.util.StringUtils;import com.fasterxml.jackson.annotation.JsonIgnoreProperties;import com.fasterxml.jackson.annotation.JsonTypeInfo;@suppresswarnings( "serial")@JsonTypeInfo(use = JsonTypeInfo.Id.NAME,property = "type")@JsonIgnoreProperties( "source")public abstract class RemoteApplicationEvent extends ApplicationEvent(private static final 0bject TRANSTENT_SOURCE= new object();private final string originService;private final String destinationService;private final String id;protected RemoteApplicationEvent({//for serialization libs like jacksonthis(TRANSIENT_SOURCE,null,null);}protected RemoteApplicationEvent(Object source,String originservice,String destinationService){super(source);this.originservice = originService;if(destinationService -=null)destinationService ="**";)1/ If the destinationService is not already a wildcard,matcheverything that follows// if there at most two path elements,and last element is nota global wildcard alreadyif(!"**".equals(destinationService)){if (StringUtils.countoccurrencesof(destinationService,":")<= 1&& !StringUtils.endsWithIgnoreCase (destinationService,":**")) {//All instances of the destination unless specificallyrequesteddestinationService = destinationService +":**;}this.destinationService = destinationService;this.id= UUID.randomUUID().toString(;protected RemoteApplicationEvent (Object source,String originService){this(source,originservice,null);}//省略 getter/setter方法}

最常用的RemoteApplicationEvent的子类,莫过于EnvironmentChangeRemoteApplicationEvent和RefreshRemoteApplicationEvent。

以下是EnvironmentChangeRemoteApplicationEvent.java的源码。

package org.springframework.cloud.bus.event;import java.util.Map;@SuppressWarnings( "serial")public class EnvironmentChangeRemoteApplicationEvent extends RemoteApplicationEvent {private final Map values;@SuppressWarnings("unused")private EnvironmentChangeRemoteApplicationEvent() {//for serializersvalues = null;public EnvironmentChangeRemoteApplicationEvent (Object source,StringoriginService,String destinationService,Map values)super(source,originService,destinationService);this.values =values;//省略 getter/setter 方法}

以下是RefreshRemoteApplicationEvent.java的源码。

package org.springframework.cloud.bus.event;@suppressWarnings("serial")public class RefreshRemoteApplicationEvent extends RemoteApplicationEvent {SuppressWarnings ("unused")private RefreshRemoteApplicationEvent( {//for serializers}public RefreshRemoteApplicationEvent(Object source,String originservice,String destinationservice){super(source, originService,destinationService);}}

3.ApplicationListener及其子类

ApplicationListener是用来处理消息事件的监听器,是Spring框架的核心接口。该接口只有一个方法。

public interface ApplicationListenerE extends ApplicationEvent> extendsEventListener {★★*Handle an application event.* @param event the event to respond to*/void onApplicationEvent(E event) ;}

Spring Cloud Bus中的监听器都需要实现该接口。EnvironmentChangeListener及RefreshListener是其中两个常用的实现类。

以下是 EnvironmentChangeListener.java的源码。

package org.springframework.cloud.bus.event;import java.util.Map;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.cloud.context.environment.EnvironmentManager;import org.springframework.context.ApplicationListener;public class EnvironmentChangeListenerimplements ApplicationListener {private static Log log = LogFactory.getLog(EnvironmentChangeListener.class);@Autowiredprivate EnvironmentManager env;aoverridepublic void onApplicationEvent(EnvironmentChangeRemoteApplicationEvent event){Map values = event.getValues();log.info ("Received remote environment change request. Keys/values to update "+values);for (Map.Entry entry : values.entrySet()){env.setProperty(entry.getKey(,entry.getvalue());}}}

以下是RefreshListener.java的源码。

package org.springframework.cloud.bus.event;import java.util.Set;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;import org.springframework.cloud.context.refresh.ContextRefresher;import org.springframework.context.ApplicationListener;public class RefreshListenerimplements ApplicationListener{private static Log log = LogFactory.getLog (RefreshListener.class);private ContextRefresher contextRefresher;public RefreshListener(ContextRefresher contextRefresher)this.contextRefresher = contextRefresher;@overridepublic void onApplicationEvent(RefreshRemoteApplicationEvent event)Set keys = contextRefresher.refresh();log.info ("Received remote refresh request.Keys refreshed " +keys);}}

本篇文章内容给大家讲解的是SpringCloudBus 设计原理

  1. 下篇文章给大家讲解的是如何集成 BuS;
  2. 觉得文章不错的朋友可以转发此文关注小编;
  3. 感谢大家的支持!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值