在我们开始讲Spring Cloud Bus之前来看另外一个IT术语:ESB(Enterprise Service Bus)。ESB在维基百科中是这样描述的:企业服务总线(Enterprise Service Bus,ESB)的概念是從服務導向架構(Service Oriented Architecture, SOA)發展而來。SOA描述了一种IT基础设施的应用集成模型;其中的软构件集是以一种定义清晰的层次化结构来相互耦合。一个ESB是一个预先组装的SOA实现,它包含了实现SOA分层目标所必需的基础功能部件。在企业计算领域,企业服务总线是指由中间件基础设施产品技术实现的、 通过事件驱动和基于XML消息引擎,为更复杂的面向服务的架构提供的软件架构的构造物。企业服务总线通常在企业消息系统上提供一个抽象层,使得集成架构师能够不用编码而是利用消息的价值完成集成工作。企业服务总线提供可靠消息传输,服务接入,协议转换,数据格式转换,基于内容的路由等功能,屏蔽了服务的物理位置,协议和数据格式。
其中,最重要的一句就是:企业服务总线通常在企业消息系统上提供一个抽象层,使得集成架构师能够不用编码而是利用消息的价值完成集成工作。 通俗一点来讲就是企业服务总线是架构在消息中间件之上的另外一个抽象层,使得我们可以不用关心消息相关的处理就可以完成业务逻辑的处理。
到这里你是不是有点突然明白Spring Cloud Bus 和 Spring Cloud Stream之间的关系了,刚开始接触这两个组件时,大部分都会迷惑到底这两者有什么区别?它们又有什么联系?Stream通过对消息中间件进行抽象封装,提供一个统一的接口供我们发送和监听消息,而Bus则是在Stream基础之上再次进行抽象封装,使得我们可以在不用理解消息发送、监听等概念的基础上使用消息来完成业务逻辑的处理。
那么Spring Cloud Bus是如何为我们实现的呢?一句话概括就是事件机制。
1. Spring的事件机制
在Spring框架中有一个事件机制,该机制是一个观察者模式的实现。观察者模式建立一种对象与对象之间的依赖关系,当一个对象(称之为:观察目标)发生改变时将自动通知其它对象(称之为:观察者),这些观察者将做出相应的反应。一个观察目标可以对应多个观察者,而且这些观察者之间没有相互联系,可以根据需要增加和删除观察者,使得系统更易于扩展。通过Spring事件机制可以达到如下目的:应用模块之间的解耦;
对同一种事件可以根据需要定义多种处理方式;
对主线应用不干扰,是一个极佳的开闭原则(OCP)实践。
当我们在应用中引入事件机制时需要借助Spring中以下接口或抽象类:ApplicationEventPublisher: 这是一个接口,用来发布一个事件;
ApplicationEvent: 这是一个抽象类,用来定义一个事件;
ApplicationListener: 这是一个接口,实现事件的监听。
其中Spring应用的上下文ApplicationContext默认是实现了ApplicationEventPublisher接口,因此在发布事件时我们可以直接使用ApplicationContext.publishEvent()方法来发送。
一个典型的Spring事件发送与监听代码如下。
1.1 定义事件
比如,我们定义一个用户事件:/**
* 用户事件
*
* @author CD826(CD826Dong@gmail.com)
* @since 1.0.0
*/public class UserEvent extends ApplicationEvent { /** 消息类型:更新用户,值为: {@value} */
public static final String ET_UPDATE = "update"; // ========================================================================
// fields =================================================================
private String action; private User user; // ========================================================================
// constructor ============================================================
public UserEvent(User user) { super(user); this.user = user;
} public UserEvent(User user, String action) { super(user); this.action = action; this.user = use