消息觸達域是一個通用域。是一個基礎組件,通過領域事件的方式將其與業務代碼進行解耦。
在不同的限定上下文中,“用戶”有着不同的含義。
在賬戶域中:用戶含義表示的是“賬戶”;
在消息域中:用戶含義表示的是“消息接收人”;
而消息實體一般有三要素:
- 發給誰;
- 發什麼;(消息內容,也可以是消息事件+填充內容)
- 發送渠道;
消息實體的能力:
- 消息send();
- 消息頻次處理;
代碼實現
消息實體
@Data
public class Message {
/**
* 消息id
*/
private String messageId;
/**
* 消息內容(發什麼)
*/
private MessageContext context;
/**
* 消息接收者(發給誰)
*/
private List<String> allNotifier;
/**
* 消息渠道(怎麼發)
*/
private ChannelEnum channel;
/**
* 消息頻次控制(觸發時機)
*/
private Predicate<Message> trigger;
public void send() {
CustomApplicationContext.getContext()
.publishEvent(new ApplicationNotifyEvent(Lists.newArrayList(this)));
}
public enum ChannelEnum {
EMAIL, //郵件
SMS; //短信
}
@Data
private static class MessageContext {
/**
* 消息事件,選填
*/
private String event;
/**
* 標頭,選填
*/
private Map<String, String> title;
/**
* 內容,必填
*/
private Map<String, String> content;
}
}
領域事件
public class ApplicationNotifyEvent extends ApplicationEvent {
private List<Message> messages;
public ApplicationNotifyEvent(List<Message> messages) {
super(messages);
this.messages = messages;
doCheckMessage(messages);
}
public List<Message> getMessages() {
return messages;
}
/**
* 校驗邏輯
*/
protected void doCheckMessage(List<Message> messages) {
}
}
消息監聽者(公共):
@Slf4j
@Service
public class BasicNotifyListener implements ApplicationListener<ApplicationNotifyEvent> {
@Override
public void onApplicationEvent(ApplicationNotifyEvent event) {
batchSendMsg(event);
}
protected void batchSendMsg(ApplicationNotifyEvent event) {
List<Message> messageEntities = event.getMessages();
if (CollectionUtils.isEmpty(messageEntities)) {
return;
}
messageEntities.forEach(this::sendMessageAsync);
}
public void sendMessageAsync(Message message) {
//消息頻次觸發控制
if (!Optional.ofNullable(message.getTrigger()).map(r -> r.test(message)).orElse(true)) {
return;
}
//todo 業務處理
}
}
工具方法
@Component
public class CustomApplicationContext<T extends ApplicationEvent> implements ApplicationContextAware {
private static ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
public static ApplicationContext getContext() {
return context;
}
public static <T> void publishEventIfNotNull(T event) {
//兼容消息爲null的場景
if (event == null) {
return;
}
context.publishEvent(event);
}
}