基于 SpringBoot + Nats 完成简单的消息推送和订阅
本文基于上一篇安装好的 Nats 进行,如未安装,请参见
官方文档:https://docs.nats.io/developing-with-nats/developer
一、Nats 相关配置
1、引入相关依赖
<dependency>
<groupId>io.nats</groupId>
<artifactId>jnats</artifactId>
<version>2.6.5</version>
</dependency>
2、配置 application.yml
server:
port: 7005
spring:
application:
name: nats
nats:
# nats 地址
nats-urls: nats://192.168.202.128:4222
# 最大重连次数
max-reconnect: 60
# 重连等待时间
reconnect-wait: 2
# 连接超时时间
connection-timeout: 2
# 用户名
user-name: nats
# 密码
password: nats
3、读取 Nats 的相关配置
package com.wxw.notes.nats.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 获取配置文件中 nats 相关配置
*/
@Component
@ConfigurationProperties(prefix = "nats")
@Data
public class NatsProperties {
private String natsUrls;
private String token = null;
private int maxReconnect = 60;
private int reconnectWait = 2;
private int connectionTimeout = 2;
private String userName;
private String password;
}
4、Nats 连接监听及消息订阅
package com.wxw.notes.nats.listener;
import io.nats.client.Connection;
import io.nats.client.ConnectionListener;
import io.nats.client.Dispatcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.invoke.MethodHandles;
import java.nio.charset.StandardCharsets;
/**
* NatsListener 连接监听
*/
public class NatsListener implements ConnectionListener {
private static final Logger LOGGER = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
/**
* 监听 nats 连接状态 ,并进行消息订阅
* @param conn
* @param type
*/
@Override
public void connectionEvent(Connection conn, Events type) {
LOGGER.info(String.format("nats connection status: %s", conn.getStatus()));
if(Connection.Status.CONNECTED.equals(conn.getStatus())){
LOGGER.info("subscribe topic");
// 连接成功后进行消息订阅
subscribe(conn);
}
}
/**
* 异步订阅
* @param conn 连接
*/
public void subscribe(Connection conn){
Dispatcher dispatcher = conn.createDispatcher(msg -> {
LOGGER.info("Received message {}, on subject {}", new String(msg.getData(), StandardCharsets.UTF_8), msg.getSubject());
});
//订阅 subject 为 NATS_TEST 的消息
dispatcher.subscribe("NATS_TEST");
// 不关闭connection,方便测试多次接收消息
}
}
5、将 Nats 注入 Spring 容器
package com.wxw.notes.nats.config;
import com.wxw.notes.nats.listener.NatsListener;
import io.nats.client.Connection;
import io.nats.client.Nats;
import io.nats.client.Options;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.io.IOException;
import java.time.Duration;
/**
* nats 连接配置类
*/
@Configuration
public class NatsConfiguration {
/**
* 注入 nats 连接
* @param properties nats 配置文件类
* @return nats 连接
* @throws IOException
* @throws InterruptedException
*/
@Bean(name = "natsConnection")
public Connection natsConnection(NatsProperties properties) throws IOException, InterruptedException {
String[] str = properties.getNatsUrls().split(",");
Options.Builder builder = new Options.Builder()
// 配置 nats 服务器地址
.servers(str)
// 配置用户名和密码
.userInfo(properties.getUserName().toCharArray(),properties.getPassword().toCharArray())
// nats 监听
.connectionListener(new NatsListener())
// 最大重连次数
.maxReconnects(properties.getMaxReconnect())
// 重连等待时间
.reconnectWait(Duration.ofSeconds(properties.getReconnectWait()))
// 连接超时时间
.connectionTimeout(Duration.ofSeconds(properties.getConnectionTimeout()));
if (properties.getToken() != null) {
builder.token(properties.getToken().toCharArray());
}
//连接 nats
return Nats.connect(builder.build());
}
}
二、Nats 消息推送
编写一个简单的 controller 进行消息推送
package com.wxw.notes.nats.controller;
import io.nats.client.Connection;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
/**
* @author wuxiongwei
* @date 2021/6/16 16:32
* @Description 测试 nats 消息推送
*/
@RestController
public class NatsController {
@Resource(name = "natsConnection")
private Connection natsConnection;
@RequestMapping("/publish")
public void publish(){
String msg = "hello nats";
// subject 为 NATS_TEST,消息内容为 msg
natsConnection.publish("NATS_TEST", msg.getBytes(StandardCharsets.UTF_8));
}
}
这里我们拿到之前注入到 spring 容器的 natsConnection 来进行消息推送
然后通过 publish 方法进行推送,
第一个参数是消息的 subject ,消息的主题,类似于 kafka 的 topic 概念;
第二个参数是消息的内容,格式为 byte[] ,我们设置编码格式为 UTF-8;
三、Nats 消息订阅
其实这个订阅在我们第一步的第4小点就已经做了,也就是这一段
/**
* 异步订阅
* @param conn 连接
*/
public void subscribe(Connection conn){
Dispatcher dispatcher = conn.createDispatcher(msg -> {
LOGGER.info("Received message {}, on subject {}", new String(msg.getData(), StandardCharsets.UTF_8), msg.getSubject());
});
//订阅 subject 为 NATS_TEST 的消息
dispatcher.subscribe("NATS_TEST");
// 不关闭connection,方便测试多次接收消息
}
这里我们采用异步的订阅方式来进行订阅,还有其他几种订阅方式,如同步订阅、接收N条之后取消订阅等,可以参阅官方文档自行尝试
四、 Nats 消息推送订阅测试
消息推送和订阅我们已经全部编写好了,接下来我们就可以开始看看成果了
运行我们的项目
可以看到我们 Nats 监听类的日志打印,已经连上了我们的 Nats 服务器,并且开始订阅了,接下来我们就需要发送一条消息,看是否能收到
浏览器访问第二步的消息推送接口:localhost:7005/publish
查看控制台,完美,消息收到了