一、引言
最近在实现微信小程序时,需要处理微信服务器推送来的不同的消息,消息类型多种多样,包括订阅消息、图文消息等等。在借鉴一些大神的设计模式后,简单实现了一种消息路由模型,可满足多种类型的消息、多种路由匹配、多种消息处理。
二、模型
-
消息本身有一些特征量,可作为消息路由规则匹配的依据。
-
一个消息路由器包含多个消息路由规则。
-
一个消息路由规则包含拦截器、匹配器,多个处理器。
三、代码
3.1 消息定义
源码:https://segmentfault.com/a/1190000039689926
待消费的消息
@Builder
@Getter
@ToString
public class Message {
private String event;
private String msgType;
private String content;
private String fromUser;
private String toUser;
private Instant createTime;
//... as you wish
}
待消费消息对象包含一些Trait
字段,包括event
,msgType
,content
。这些字段既可以作为路由规则匹配的依据,也能作为具体消息处理的条件。可根据不同的业务类型去扩展。
消息处理结果
@Builder
@ToString
public class OutMessage {
private String msgType;
private String fromUser;
private String toUser;
private Instant createTime;
}
消息处理结果,根据具体业务自行定义吧。
3.2 消息处理器
抽象类型
public interface MessageHandler {
OutMessage handle(Message message, Map<String,Object> context);
}
这是所有消息处理器的抽象类型,自定义的处理器都必须实现它。简单实现一个消息日志记录处理器。
@Component
public class LogMessageHandler implements MessageHandler {
@Override
public OutMessage handle(Message message, Map<String, Object> context) {
System.out.println(message.toString());
// define your return value
return null;
}
}
3.2 路由相关
消息拦截器
public interface MessageInterceptor {
OutMessage handle(Message message, Map<String,Object> context);
}
拦截器可增强对消息处理。自行实现此接口。
消息匹配器
public interface MessageRouterMatcher {
boolean match(Message message);
}
匹配器可实现对消息的过滤,以实现对消息的规则匹配。
路由器
public class MessageRouter {
@Getter
private final List<MessageRouterRule> rules = new ArrayList<>();
public MessageRouterRule rule(){
return new MessageRouterRule(this);
}
private OutMessage route(Message message,Map<String,Object> context){
final List<MessageRouterRule> matchRules = new ArrayList<>();
final Iterator<MessageRouterRule> iterator = this.rules.iterator();
while (iterator.hasNext()){
final MessageRouterRule rule = iterator.next();
if (rule.test(message)){
matchRules.add(rule);
}
}
if(matchRules.size() == 0){
return null;
}else{
final Iterator<MessageRouterRule> matchIterator = matchRules.iterator();
while (matchIterator.hasNext()){
final MessageRouterRule rule = matchIterator.next();
//think think multi OutMessage
return rule.service(message, context);
}
}
return null;
}
public OutMessage route(Message message){
return this.route(message,new HashMap<>(2));
}
}
public class MessageRouterRule {
//是否异步处理消息
private boolean async;
private String event;
private String msgType;
private String content;
private String fromUser;
private String toUser;
/**
* 路由器
*/
private MessageRouter router;
/**
* 匹配器
*/
private MessageRouterMatcher matcher;
/**
* 处理器
*/
private List<MessageHandler> handlers = new ArrayList<>();
/**
* 拦截器
*/
private List<MessageInterceptor> interceptors = new ArrayList<>();
public MessageRouterRule async(boolean async){
this.async = async;
return this;
}
public MessageRouterRule msgType(String msgType){
this.msgType = msgType;
return this;
}
public MessageRouterRule event(String event){
this.event = event;
return this;
}
public MessageRouterRule content(String content){
this.content= content;
return this;
}
public MessageRouterRule fromUser(String fromUser){
this.fromUser= fromUser;
return this;
}
public MessageRouterRule toUser(String toUser){
this.toUser= toUser;
return this;
}
public MessageRouterRule handler(MessageHandler handler,MessageHandler... otherHandlers){
this.handlers.add(handler);
if(otherHandlers != null && otherHandlers.length>0){
Collections.addAll(this.handlers,otherHandlers);
}
return this;
}
public MessageRouterRule handle(MessageHandler handler){
return this.handler(handler,(MessageHandler[]) null);
}
public MessageRouter end(){
this.router.getRules().add(this);
return this.router;
}
protected boolean test(Message message){
//here can use matcher
return (this.fromUser == null || this.fromUser.equals(message.getFromUser())) && (this.msgType == null || this.msgType.toLowerCase().equals(message.getMsgType() == null ? null : message.getMsgType().toLowerCase())) && (this.event == null || this.event.toLowerCase().equals(message.getEvent() == null ? null : message.getEvent().toLowerCase())) && (this.content == null || this.content.equals(message.getContent() == null ? null : message.getContent().trim())) && (this.matcher == null || this.matcher.match(message));
}
public MessageRouterRule(MessageRouter router){
this.router = router;
}
protected OutMessage service(Message message, Map<String,Object> context){
OutMessage outMessage = null;
final Iterator<MessageHandler> iterator = handlers.iterator();
while (iterator.hasNext()){
final MessageHandler handler = iterator.next();
if(null != handler){
outMessage = handler.handle(message,context);
}
}
return outMessage;
}
}
消息路由器中包含多种消息路由规则。
消息路由规则通过拦截器增强都消息的处理,通过匹配器实现对消息的过滤匹配。同时集成多个处理器,以完成对消息的最终处理。
四、测试
本次测试使用的是spring
框架。
先实现一个配置类bean
@Configuration
public class MessageRouterConfiguration {
final LogMessageHandler logMessageHandler;
public MessageRouterConfiguration(LogMessageHandler logMessageHandler) {
this.logMessageHandler = logMessageHandler;
}
@Bean
@ConditionalOnMissingBean(value = MessageRouter.class)
public MessageRouter newRouter(){
final MessageRouter messageRouter = new MessageRouter();
//log print router rule
messageRouter.rule().async(false).event("event").handle(logMessageHandler).end();
//... add more
return messageRouter;
}
}
消息路由调用
在应用入口路由消息,得到结果
final OutMessage outMessage = router.route(message);
最终在终端会打印日志信息。
五、总结
本模型只实现了一个简单的消息路由模型,还有很多待完善的地方,例如
- 处理多个消息处理器的执行结果
- 异步处理消息
- 消息可能会重复消费
- ...
等下一个迭代再优化吧!欢迎留言沟通。