One, the introduction

Recently, in the realization of wechat small program, we need to deal with different messages pushed by wechat server. There are a variety of message types, including subscription messages, graphic messages and so on. After referring to the design patterns of some great gods, a message routing model is simply implemented, which can meet the requirements of various types of messages, route matching and message processing.

Second, the model

  • The message itself has some characteristics, which can be used as the basis of the matching of message routing rules.

  • A message router contains multiple message routing rules.

  • A message routing rule contains interceptors, matchers, and multiple handlers.

Three, code,

3.1 Message Definition

News of pending consumption

@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 }Copy the code

The message object to be consumed contains Trait fields, including Event, msgType, and Content. These fields can be used as a basis for routing rule matching or as a condition for specific message processing. It can be extended according to different business types.

Message processing results

@Builder
@ToString
public class OutMessage {
    private String msgType;
    private String fromUser;
    private String toUser;
    private Instant createTime;
}
Copy the code

The message processing results are customized for your business.

3.2 Message Handlers

Abstract type

public interface MessageHandler {
    OutMessage handle(Message message, Map<String,Object> context);
}
Copy the code

This is an abstract type for all message handlers, and custom handlers must implement it. Simple implementation of a message logging handler.

@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; }}Copy the code

3.2 Route Correlation

Message interceptor

public interface MessageInterceptor {
    OutMessage handle(Message message, Map<String,Object> context);
}
Copy the code

Interceptors enhance message processing. Implement this interface yourself.

Message adapter

public interface MessageRouterMatcher {
    boolean match(Message message);
}
Copy the code

Matchers can filter messages to match rules of messages.

The router

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)); }}Copy the code

Message routing rules

Public class MessageRouterRule {// Whether to process messages asynchronously private Boolean async; private String event; private String msgType; private String content; private String fromUser; private String toUser; /** * private MessageRouter router; /** ** private MessageRouterMatcher matcher; Handlers = new ArrayList<>(); Private List<MessageInterceptor> interceptors = 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; }}Copy the code

Message routers contain a variety of message routing rules.

Message routing rules enhance message processing through interceptors and filter and match messages through matchers. Integrate multiple processors simultaneously to complete the final processing of messages.

Four, test,

The Spring framework was used for this test.

Start by implementing a configuration class 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;
    }
}
Copy the code

Message routing call

Route the message in the application entry and get the result

final OutMessage outMessage = router.route(message);
Copy the code

Finally, logs are displayed on the terminal.

Five, the summary

This model only implements a simple message routing model, there are still many areas to be improved, for example

  • Process the execution results of multiple message handlers
  • Asynchronously processing messages
  • Messages may be consumed repeatedly
  • .

Optimize it in the next iteration! Welcome to leave a message.