I. Introduction
Recently, when implementing WeChat applets, it is necessary to process different messages pushed from the WeChat server. There are many types of messages, including subscription messages, graphic messages, and so on. After learning from some design patterns of great gods, a simple message routing model is implemented, which can meet multiple types of messages, multiple routing matching, and multiple message processing.
Two, the model
-
The message itself has some characteristic quantities, which can be used as the basis for matching message routing rules.
-
A message router contains multiple message routing rules.
-
A message routing rule includes interceptors, matchers, and multiple processors.
Three, the code
3.1 Message definition
Source code: https://segmentfault.com/a/1190000039689926
Message to be consumed
@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
}
Consumer information to be object contains a number of Trait
fields, including event
, msgType
, content
. These fields can be used not only as the basis for matching routing rules, but also as conditions for processing specific messages. It can be expanded according to different business types.
Message processing result
@Builder
@ToString
public class OutMessage {
private String msgType;
private String fromUser;
private String toUser;
private Instant createTime;
}
Define the message processing result according to your specific business.
3.2 Message processor
Abstract type
public interface MessageHandler {
OutMessage handle(Message message, Map<String,Object> context);
}
This is an abstract type of all message processors, and custom processors must implement it. Simply implement a message logging processor.
@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 Routing related
Message interceptor
public interface MessageInterceptor {
OutMessage handle(Message message, Map<String,Object> context);
}
Interceptors can enhance the processing of messages. Implement this interface yourself.
Message matcher
public interface MessageRouterMatcher {
boolean match(Message message);
}
The matcher can filter the message to realize the rule matching of the message.
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));
}
}
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;
}
}
The message router contains a variety of message routing rules.
Message routing rules enhance the processing of all messages through interceptors, and filter and match messages through matchers. Integrate multiple processors at the same time to complete the final processing of the message.
Four, test
This test uses a spring
framework.
First implement a configuration classbean
@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;
}
}
Message routing call
Route messages at the entrance of the application and get the result
final OutMessage outMessage = router.route(message);
Eventually, the log information will be printed on the terminal.
Five, summary
This model only implements a simple message routing model, and there are still many areas to be improved, such as
- Handle the execution results of multiple message processors
- Process messages asynchronously
- Messages may be repeatedly consumed
- ...
Wait for the next iteration to optimize! Welcome to leave a message to communicate.