使用spring事件完成消息推送功能
需求是查询数据库 ,有无用户未读的消息,发消息通知前端。
第一版:
使用订阅者模式,一个线程轮询数据库是否有新消息,有则放入session属性中;一个线程拉,一直轮询这个session属性,有则通知前端。
拉 :
@OnOpen public String open(Session session) { Cache cache = cacheManager.getCache(EhCacheName.CONST); openSessions.add(session);if (session.getUserProperties().get("eventQueue")==null) { session.getUserProperties().put("eventQueue", new LinkedBlockingQueue()); } if ( cache.get(session.getId() + "sentResponseForm")==null){ cache.put(session.getId() + "sentResponseForm",new ArrayList<>()); } if (!isEventOpen) { Thread eventQueuePoller = new Thread(() -> { //每一用户单独队列 LinkedBlockingQueue queue = (LinkedBlockingQueue) session.getUserProperties().get("eventQueue"); while (true) { ResponseForm responseForm = (ResponseForm) queue.poll(); if (responseForm != null) { session.getAsyncRemote().sendText(JSON.toJSONString(responseForm)); } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } }); eventQueuePoller.setName("eventQueuePoller"); eventQueuePoller.start(); //判断 new MessageListener(session, messageService, cacheManager).listen(); isEventOpen = true; } return "open"; }
其中@OnMessage是J2EE websocket注解,ResponseForm 是自定义的数据格式 。
推:轮询数据库,往队列里添加ResponseForm 。
功能虽然能完成,可是存在问题:1.有新消息就一直往前端推送,直到消息被阅读,影响用户体验。2.无关代码放在一个功能里
解决方法:
第一个问题,使用缓存比对,即查询出来的和 缓存中比对,有新的才通知。
第二个问题,使用spring自带的消息通知,其实在spring启动过程中已经使用过了,只是不知道。
推的线程不变,但是不需要用户队列,取而代之得是
ApplicationContext.publishEvent(event);
然后所有实现了EventListener的类都会得到消息通知。
从实现的角度 来说,区别就在于我通过一个队列订阅消息,可以并发往队列里加消息,而 spring的实现可以无需代码对多个订阅者通知。
参考文章:https://jinnianshilongnian.iteye.com/blog/1902886