1. 提供订阅者发布者客户端抽象
public abstract void send(String topic, String msg); public abstract void send(String msg); public abstract void bind(); public abstract void shutdown(); public abstract void subscribe(String topic); public abstract void unsubscribe(String topic);
2. 实现发布者客户端实例
package com.wetlinks.context.framework.jeromq;
import com.wetlinks.context.framework.beans.BeanUtils;
import lombok.extern.slf4j.Slf4j;
import org.zeromq.SocketType;
import org.zeromq.ZContext;
import org.zeromq.ZMQ;
import java.util.Optional;
@Slf4j
public class WetlinksJeromqPublisher extends WetlinksJeromqClient {
private ZContext context = new ZContext(1);
private ZMQ.Socket socket;
private WetlinksJeromqCallback callback;
private String host;
private String port;
public WetlinksJeromqPublisher(WetlinksJeromqCallback callback, String host, String port, SocketType socketType) {
this.callback = callback;
this.host = host;
this.port = port;
this.socket = context.createSocket(socketType);
}
@Override
public void bind(){
socket.monitor("inproc://reqmoniter",ZMQ.EVENT_ALL);
callback.bind(context, socket.getSocketType());
socket.bind("tcp://" + this.host + ":" + this.port);
log.info("[ 物联网关 ] {}: 启用成功", BeanUtils.getSocketType(socket.getSocketType()));
}
@Override
public void shutdown(){
if (socket == null){
socket = Optional.ofNullable(socket).orElse(context.createSocket(SocketType.PUB));
}
this.socket.close();
this.context.close();
}
@Override
public void subscribe(String topic) {
socket.subscribe(topic.getBytes());
}
@Override
public void unsubscribe(String topic) {
socket.unsubscribe(topic.getBytes());
}
@Override
public void send(String topic, String msg) {
socket.send((topic + " " + msg ).getBytes());
}
@Override
public void send(String msg) {
socket.send((msg).getBytes());
}
}
3. 实现订阅者客户端实例
package com.wetlinks.context.framework.jeromq;
import com.wetlinks.context.framework.beans.BeanUtils;
import lombok.extern.slf4j.Slf4j;
import org.zeromq.SocketType;
import org.zeromq.ZContext;
import org.zeromq.ZMQ;
import java.util.Optional;
@Slf4j
public class WetlinksJeromqSubscriber extends WetlinksJeromqClient {
private ZContext context = new ZContext(1);
private ZMQ.Socket socket;
private WetlinksJeromqCallback callback;
private String host;
private String port;
public WetlinksJeromqSubscriber(WetlinksJeromqCallback callback, String host, String port, SocketType socketType) {
this.callback = callback;
this.host = host;
this.port = port;
this.socket = context.createSocket(socketType);
}
@Override
public void bind(){
socket.monitor("inproc://reqmoniter",ZMQ.EVENT_ALL);
callback.bind(context, socket.getSocketType());
socket.connect("tcp://" + this.host + ":" + this.port);
subscribe("");
log.info("[ 物联网关 ] {}: 启用成功", BeanUtils.getSocketType(socket.getSocketType()));
}
@Override
public void shutdown(){
if (socket == null){
socket = Optional.ofNullable(socket).orElse(context.createSocket(SocketType.PUB));
}
callback.shutdown(socket.getSocketType());
this.socket.close();
this.context.close();
}
@Override
public void send(String topic, String msg) {
socket.send((topic + " " + msg ).getBytes());
}
@Override
public void send(String msg) {
socket.send((msg).getBytes());
}
@Override
public void subscribe(String topic) {
socket.subscribe(topic.getBytes());
}
@Override
public void unsubscribe(String topic) {
socket.unsubscribe(topic.getBytes());
}
public void bind(WetlinksJeromqMessageChanel messagePipeline) {
socket.monitor("inproc://reqmoniter",ZMQ.EVENT_ALL);
callback.bind(context, socket.getSocketType());
socket.connect("tcp://" + this.host + ":" + this.port);
subscribe("asd");
log.info("[ 物联网关 ] {}: 启用成功", BeanUtils.getSocketType(socket.getSocketType()));
messagePipeline.channelRead(socket);
}
public void bind(WetlinksJeromqMessageChanel messagePipeline, String topic) {
socket.monitor("inproc://reqmoniter",ZMQ.EVENT_ALL);
callback.bind(context, socket.getSocketType());
socket.connect("tcp://" + this.host + ":" + this.port);
subscribe(topic);
log.info("[ 物联网关 ] {}: 启用成功", BeanUtils.getSocketType(socket.getSocketType()));
messagePipeline.channelRead(socket, topic);
}
}
4. 开启异步线程监听客户端实例通信状态
public interface WetlinksJeromqCallback {
void bind(ZContext context, SocketType socketType);
void shutdown(SocketType socketType);
}
package com.wetlinks.context.framework.jeromq;
import java.util.concurrent.ConcurrentHashMap;
public class WetlinksJeromqConcurrentHashMap extends ConcurrentHashMap<Integer, WetlinksJeromqPipeline> {
}
package com.wetlinks.context.framework.jeromq;
import com.wetlinks.context.framework.beans.BeanUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.zeromq.SocketType;
import org.zeromq.ZContext;
import org.zeromq.ZMQ;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@Component
public class WetlinksJeromqMonitorChannel extends Thread implements WetlinksJeromqCallback {
private final WetlinksJeromqConcurrentHashMap eventGroup;
private final Map<SocketType, Boolean> threadManageHashMap = new ConcurrentHashMap<>();
public WetlinksJeromqMonitorChannel(List<WetlinksJeromqPipeline> eventPipeline, WetlinksJeromqConcurrentHashMap eventGroup) {
this.eventGroup = eventGroup;
eventPipeline.forEach(p -> eventGroup.put(p.getEventId(), p));
}
@Async(value = "WetlinksAsync")
@Override
public void bind(ZContext context, SocketType socketType) {
threadManageHashMap.put(socketType, Boolean.TRUE);
final ZMQ.Socket moniter = context.createSocket(SocketType.PAIR);
moniter.connect("inproc://reqmoniter");
while (threadManageHashMap.get(socketType)){
ZMQ.Event event = null;
try {
event = ZMQ.Event.recv(moniter);
}catch (Exception e){
continue;
}
if (event == null){
continue;
}
int code = event.getEvent();
if (!eventGroup.containsKey(code)){
continue;
}
eventGroup.get(code).processor(socketType);
}
System.out.println(BeanUtils.getSocketType(socketType) + ":退出线程 - " + this.getClass().getSimpleName());
}
@Override
public void shutdown(SocketType socketType) {
threadManageHashMap.put(socketType, Boolean.FALSE);
}
}
5. 开启异步线程获取消息,并通过观察者模式将消息处理进行处理
@Component
@RequiredArgsConstructor
public class WetlinksJeromqMessageChanel {
private final ApplicationEventPublisher eventPublisher;
@Async(value = "WetlinksAsync")
public void channelRead(ZMQ.Socket socket){
SocketType socketType = socket.getSocketType();
while (socket != null){
try {
String message = socket.recvStr();
eventPublisher.publishEvent(new WetlinksJeromqMessageEvent(message.trim(), socketType));
}catch (Exception e){
socket.close();
break;
}
}
System.out.println(BeanUtils.getSocketType(socketType) + ":退出线程 - " + this.getClass().getSimpleName());
}
@Async(value = "WetlinksAsync")
public void channelRead(ZMQ.Socket socket, String topic) {
SocketType socketType = socket.getSocketType();
while (socket != null){
try {
String message = socket.recvStr();
message = message.substring(topic.length() + 1, message.length());
eventPublisher.publishEvent(new WetlinksJeromqMessageEvent(message.trim(), socketType));
}catch (Exception e){
socket.close();
break;
}
}
System.out.println(BeanUtils.getSocketType(socketType) + ":退出线程 - " + this.getClass().getSimpleName());
}
}
6. 事件监听器处理监听消息
package com.wetlinks.context; import lombok.Getter; import org.springframework.context.ApplicationEvent; import org.zeromq.SocketType; @Getter public class WetlinksJeromqMessageEvent extends ApplicationEvent{ private SocketType socketType; public WetlinksJeromqMessageEvent(Object source, SocketType socketType) { super(source); this.socketType = socketType; } } @Slf4j @Component @RequiredArgsConstructor public class WetlinksJeromqMessageListener { @EventListener public void processor(WetlinksJeromqMessageEvent messageEvent){ log.info("[ 物联网关 ] {}: 接收到消息总线的消息 - {} - ", BeanUtils.getSocketType(messageEvent.getSocketType()), messageEvent.getSource() ); } }
7. 运行示例
package com.wetlinks.autoconfigure;
import com.wetlinks.context.framework.jeromq.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import org.zeromq.SocketType;
@Slf4j
@Component
@RequiredArgsConstructor
public class WetlinksJeromqConfiguration implements ApplicationRunner {
private final WetlinksJeromqCallback callback;
private final WetlinksJeromqChannelGroup channelGroup;
private final WetlinksJeromqMessageChanel messageChanel;
@Override
public void run(ApplicationArguments args) throws Exception {
WetlinksJeromqPublisher publisher = new WetlinksJeromqPublisher(callback, "192.168.6.21", "8896", SocketType.PUB);
publisher.bind();
channelGroup.put(SocketType.PUB, publisher);
WetlinksJeromqSubscriber subscriber = new WetlinksJeromqSubscriber(callback, "192.168.6.108", "8896", SocketType.SUB);
subscriber.bind(messageChanel, "hyq-dwjz");
channelGroup.put(SocketType.SUB, subscriber);
}
}