Spring Event使用@EventListener与void方法实现观察者模式遇阻求助
Spring 观察者模式实现步骤(MongoDB通知场景)
1. 定义自定义事件类
先确保你的自定义事件正确继承Spring的ApplicationEvent,用来携带通知业务所需的全部数据:
import org.springframework.context.ApplicationEvent; public class NotificationEvent extends ApplicationEvent { private String targetUserId; // 接收通知的用户ID private String content; // 通知内容 private String commentId; // 关联的评论ID(根据业务调整字段) // 必须调用父类构造,source为事件源(比如当前CommentService实例) public NotificationEvent(Object source, String targetUserId, String content, String commentId) { super(source); this.targetUserId = targetUserId; this.content = content; this.commentId = commentId; } // Getter方法,供监听器获取事件数据 public String getTargetUserId() { return targetUserId; } public String getContent() { return content; } public String getCommentId() { return commentId; } }
2. 在CommentService中发布事件
通过构造方法注入ApplicationEventPublisher,在业务逻辑完成后发布自定义事件:
import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; @Service public class CommentService { private final ApplicationEventPublisher eventPublisher; // 构造方法注入(推荐替代字段注入) public CommentService(ApplicationEventPublisher eventPublisher) { this.eventPublisher = eventPublisher; } // 示例业务方法:新增评论后触发通知 public void addComment(String postId, String commentContent, String authorId, String targetUserId) { // 1. 先执行保存评论到MongoDB的逻辑 Comment comment = new Comment(); comment.setPostId(postId); comment.setContent(commentContent); comment.setAuthorId(authorId); // 假设已完成保存,拿到生成的commentId String commentId = comment.getId(); // 2. 发布事件,传递通知所需数据 eventPublisher.publishEvent(new NotificationEvent(this, targetUserId, "你收到一条新评论:" + commentContent, commentId)); } }
3. 在NotificationService中监听事件并处理
让@EventListener方法直接接收自定义的NotificationEvent作为参数,Spring会自动完成事件与监听器的关联:
import org.springframework.context.event.EventListener; import org.springframework.stereotype.Service; import java.util.Date; @Service public class NotificationService { private final NotificationRepository notificationRepository; public NotificationService(NotificationRepository notificationRepository) { this.notificationRepository = notificationRepository; } // 监听NotificationEvent,事件发布时自动执行 @EventListener public void handleNotificationEvent(NotificationEvent event) { // 从事件对象中提取数据 String targetUserId = event.getTargetUserId(); String content = event.getContent(); String commentId = event.getCommentId(); // 3. 创建通知文档并保存到MongoDB Notification notification = new Notification(); notification.setUserId(targetUserId); notification.setContent(content); notification.setCommentId(commentId); notification.setRead(false); // 标记未读 notification.setCreateTime(new Date()); notificationRepository.save(notification); // 如需推送到前端,可在此加入WebSocket等推送逻辑 } }
关键注意点
- 自定义事件必须继承
ApplicationEvent,若仅需传递单个数据对象,也可直接发布对象本身,监听器接收对应类型即可(Spring会自动包装为PayloadApplicationEvent) - 监听器方法的参数类型必须与发布的事件类型完全匹配,Spring依据类型自动路由事件
- 确保
CommentService和NotificationService都被Spring容器管理(添加@Service注解) - 若业务方法在事务中,可使用
@TransactionalEventListener控制事件执行时机(比如@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT),确保事务提交后再生成通知)
内容的提问来源于stack exchange,提问作者mimi1907
相关产品推荐
相关产品推荐

