Vert.x(vertx) 事件总线(EventBus)与 远程服务调用

Event Bus(事件总线) 是Vert.x的神经系统,负责应用系统消息的传递。Vert.x各模块(Verticle)之间的相互调用就是通过Event Bus实现的,因此各Verticle之间是高度解耦的。

Event Bus提供发布订阅功能和点对点的消息服务,类似于消息队列,每条消息在Event Bus上都有一个地址(address),发布者向这个地址发送消息,接收者从这个地址接收消息。

Event Bus独立于应用系统,它使用TCP协议进行通信。因此,在任何的应用中,只要能够创建TCP连接,都可以通过Event Bus连接到Vert.x实例,如下图所示。也正是因为这个,Vert.x天生就对分布式支持非常好。

Event Bus的api使用非常简单,下面我们分别从获取Event Bus实例,发布消息,订阅消息以及服务调用来逐一说明。

1. 获取Event Bus实例

获取Event Bus实例非常简单,直接通过Vert.x实例获取,代码如下

EventBus eb = vertx.eventBus();

可以看到,通过Vert.x实例获取Event Bus的实例和获取文件系统fileSystem以及创建HTTP服务createHttpServer非常类似。拿到Event Bus的实例之后,发现Event Bus和Vertx一样,都是接口,查看接口的代码可以非常清楚的看到Event Bus对外提供的API,代码如下

@Fluent
EventBus send(String address, Object message);

@Fluent
EventBus publish(String address, Object message);

<T> MessageConsumer<T> consumer(String address);

为了节约篇幅,去掉了部分重载的方法。主要的几个方法send,publish,consumer,sender,publisher通过方法的名字就可以猜测出方法的用途,后面根据具体的场景来分别对这些方法进行说明。

2.发布消息

发布消息的方法有多个方法的重载,最简单的发布方法接收一个地址,和一个Object类型的消息对象,如下所示

@Fluent
EventBus publish(String address, Object message);

这种方式发布的消息,所有订阅到address的消费者都能够收到消息,这也就是发布-订阅模式。还有一种是点对点模式,这种模式发布的消息只能有一个消费者收到,方法如下

@Fluent
<T> EventBus send(String address, Object message,
 DeliveryOptions options, Handler<AsyncResult<Message<T>>> replyHandler);

3.订阅消息

对于订阅消息比较简单,只有一个方法,就是consumer,方法的声明如下

<T> MessageConsumer<T> consumer(String address, Handler<Message<T>> handler);

如果想要通过其他的开发语言或者在其他应用中调用Vert.x实例模块,可以通过发起TCP请求,连接到EventBus,Event Bus使用的通信协议如下,但一定不要忘记,需要创建Event Bus Bride。

<Length: uInt32><{

  type: String,

  address: String,

  (replyAddress: String)?,

  headers: JsonObject,

  body: JsonObject

}: JsonObject>

4.远程服务调用

最后,附一个使用Event Bus进行远程组件调用的Demo,这里例子相对来讲可能有些复杂,但相比较真实企业项目还差的远。这个例子就是一个简单的微服务,多个服务通过Event Bus进行通信。

我们把每个Verticle单独为一个Maven模块,这个模块中核心有三个类,一个Verticle,一个对外暴露的接口Interface,一个接口的具体实现类。为了简单,这里只有两个模块。

1.第一个Verticle是对外提供服务的,暂且称之为FirstVerticle,对外提供一个sayHello服务,模块结构如下

(1)FirstVerticle中就是发布Service到总线上,代码非常简单,这里只列出start方法的代码

@Override
public void start() throws Exception {
	Service service = Service.create(vertx);
	new ServiceBinder(vertx).setAddress(address).register(Service.class, service);
}

发布服务,并没有调用consumer方法,而是调用了ServiceBinder类的register方法,实际上这个方法的底层就是在调用consumer方法,只是帮我们做了很多的其实事情,这里暂且不去关注。

(2)Service接口中定义sayHello方法,并且提供了获取当前实例的方法(JDK8的新特性)

@ProxyGen
@VertxGen
public interface Service {

    /**
     * 这个方法是提供给自己使用,方便创建服务的实现类
     *
     * @param vertx
     * @return
     */
    static Service create(Vertx vertx) {
        return new ServiceImpl(vertx);
    }

    /**
     * 这个方法给消费者使用,便于消费者创建生产者的代理类,以此来消费生产者的服务
     *
     * @param vertx
     * @param address
     * @return
     */
    static Service createProxy(Vertx vertx, String address) {
        return new ServiceVertxEBProxy(vertx, address);
    }

    /**
     * 测试接口方法
     *
     * @param name
     */
    void sayHello(String name, Handler<AsyncResult<JsonObject>> resultHandle);

}

这里有三个方法,create方法是为了便于获得类的实例,这个比较好理解。createProxy方法实际上在我们当前的演示案例中并没有使用到,这里读者可以先不用去关注。对于sayHello方法的resultHandle这个参数可能不是很理解,这个参数非常简单,因为Vert.x是一个异步框架,sayHello方法也是异步执行的,那么方法的返回结构就是通过这个参数封装的。

(3)ServiceImpl的实现类的代码就更简单了,就一个sayHello方法的实现,如下

@Override
public void sayHello(String name, Handler<AsyncResult<JsonObject>> resultHandle) {
	resultHandle.handle(Future.succeededFuture(new JsonObject().put("msg", "SUCCESS")));
}

给调用者回了个Json对象,这个对象中包含一个msg,值为SUCCESS

(4)还有四,不就上面三个吗,还有一个很关键的部分,package-info

@ModuleGen(groupPackage = "stu.vertx.cluster.service.hello", name = "FirstVerticle")
package stu.vertx.cluster.service.hello;

import io.vertx.codegen.annotations.ModuleGen;

这里描述的是这个模块的包,这个是必须的,否则ServiceProxy不能生成,其他的也都是白扯。所以这里,很关键,很关键,很关键。

2.第一个组件就完成了,下面是第二个组件,第二个组件来调用第一个组件,完成一系列操作。这个组件接收客户端请求,然后接收客户端上送的name属性,传递给第二个组件,并拿到第二个组件的返回值。这个组件不对外提供服务,因此就一个Verticle就可以了。代码如下

@Override
public void start() throws Exception {
	HttpServer httpServer = vertx.createHttpServer();

	httpServer.requestHandler(request -> {

		// 获取到response对象
		HttpServerResponse response = request.response();

		// 设置响应头
		response.putHeader("Content-type", "text/html;charset=utf-8");

		// 通过配置action参数,指定要走哪一个方法
		DeliveryOptions options = new DeliveryOptions();
		options.addHeader("action", "sayHello");

		// 这个是给方法传入的参数
		JsonObject config = new JsonObject();
		config.put("name", "xiaozhang");

		// 通过eventBus调用方法
		vertx.eventBus().<JsonObject>send("service.demo.firstverticle", config, options, res -> {
			// 响应数据
			response.end(res.result().body().getString("msg"));
		});

	});

	httpServer.listen(1234);
}

OK,到这里,一个远程服务调用就完成了,是不是非常简单!

(一)Vert.x 简明介绍 Vert.x(vertx) 简明介绍_jhappyfly的博客-CSDN博客

(二)Vert.x创建简单的HTTP服务 Vert.x(vertx) 创建HTTP服务_jhappyfly的博客-CSDN博客

(三)Vert.x Web开发之路由 Vert.x(vertx) Web开发-路由_vert.x web开发_jhappyfly的博客-CSDN博客

(四)Vert.x TCP服务实现 Vert.x(vertx) 实现TCP服务_vertx怎么在任意地方写数据到tcp连接_jhappyfly的博客-CSDN博客

(五)Vert.x数据库访问 Vert.x(vertx) 连接MySQL、Oracle数据库_vertx mybatis_jhappyfly的博客-CSDN博客

(六)Vert.x认证和授权 Vert.x(vertx) 认证和授权详解(包含认证和授权在Web系统中的使用)_vertx auth_jhappyfly的博客-CSDN博客

(七)Vert.x事件总线(Event Bus)与远程服务调用 Vert.x(vertx) 事件总线(EventBus)与 远程服务调用_vertx.eventbus_jhappyfly的博客-CSDN博客

Vert.x 案例代码:https://github.com/happy-fly

评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值