You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 21:45:35