一种可扩展的消息路由实现方式

一、引言

最近在实现微信小程序时,需要处理微信服务器推送来的不同的消息,消息类型多种多样,包括订阅消息、图文消息等等。在借鉴一些大神的设计模式后,简单实现了一种消息路由模型,可满足多种类型的消息、多种路由匹配、多种消息处理。

二、模型

image.png

  • 消息本身有一些特征量,可作为消息路由规则匹配的依据。

  • 一个消息路由器包含多个消息路由规则。

  • 一个消息路由规则包含拦截器、匹配器,多个处理器。

三、代码

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字段,包括eventmsgTypecontent。这些字段既可以作为路由规则匹配的依据,也能作为具体消息处理的条件。可根据不同的业务类型去扩展。

消息处理结果

@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);

最终在终端会打印日志信息。

五、总结

本模型只实现了一个简单的消息路由模型,还有很多待完善的地方,例如

  • 处理多个消息处理器的执行结果
  • 异步处理消息
  • 消息可能会重复消费
  • ...

等下一个迭代再优化吧!欢迎留言沟通。

猜你喜欢

转载自blog.csdn.net/qq_38082146/article/details/115091385