• 深入理解SpringBoot事件机制
  • 发布于 1个月前
  • 92 热度
    0 评论
Spring Boot的事件机制是基于Spring框架的事件机制实现的。Spring Boot中的事件机制可以让我们在应用程序中监听和响应特定的事件,例如应用程序启动、关闭、上下文刷新等。接下来,我们通过一个案例,来讲解具体怎么使用。这个案例就是李莫愁给张无忌点赞。

初窥门径
首先,我们需要定义一个点赞事件类,用于表示朋友圈状态被点赞的事件:
public class LikeEvent {
    private String statusId; // 朋友圈状态的ID
    private String liker; // 点赞者的微信号
    // 堆代码 duidaima.com
    public LikeEvent(String statusId, String liker) {
        this.statusId = statusId;
        this.liker = liker;
    }

    public String getStatusId() {
        return statusId;
    }

    public String getLiker() {
        return liker;
    }
}
然后,我们需要定义一个朋友圈状态类,用于表示朋友圈中的一条状态:
@Data
public class Status {
    private String id; // 状态的ID
    private String userName; // 发布人
    private String content; // 状态的内容
    private List<String> likes; // 点赞者的微信号列表

    public Status(String id,String userName, String content) {
        this.id = id;
        this.userName = userName;
        this.content = content;
        this.likes = new ArrayList<>();
    }

    
}
接下来,我们需要定义一个朋友圈服务类,用于发布朋友圈状态和处理点赞事件:
@Service
public class MomentsService {
    public static Map<String, Status> statuses = new HashMap<>(); // 朋友圈状态的ID到状态对象的映射

    @Autowired
    private ApplicationEventPublisher publisher; // 事件发布器

    public String postStatus(String userName , String content) {
        String id = UUID.randomUUID().toString(); // 生成一个随机的ID
        Status status = new Status(id, userName,content);
        statuses.put(id, status);
        return id;
    }

    public void likeStatus(String statusId, String liker) {
        Status status = statuses.get(statusId);
        if (status != null) {
            status.addLike(liker);
            publisher.publishEvent(new LikeEvent(statusId, liker)); // 发布点赞事件
        }
    }


}
在这个服务类中,我们使用了Spring的事件机制来处理点赞事件。当一个朋友圈状态被点赞时,我们会发布一个点赞事件。
然后,我们专门定义一个监听器类,用来处理点赞事件。
@Component
public class MomentsListener {
    @EventListener
    public void handleLikeEvent(LikeEvent event) {
        String statusId = event.getStatusId();
        String liker = event.getLiker();
        Status status = statuses.get(statusId);
        if (status != null) {
            System.out.println(liker + " 点赞了 " + status.getUserName() + "的动态:" + status.getContent());
            System.out.println("当前点赞列表:" + status.getLikes());

        }
    }
}
测试:
@Resource
MomentsService momentsService;

@Test
public void testEvent(){
    User user1 = User.builder().userName("张无忌").build();
    User user2 = User.builder().userName("李莫愁").build();
    User user3 = User.builder().userName("周芷若").build();
    //发张无忌布一条动态,返回朋友圈状态ID
    String statusId = momentsService.postStatus(user1.getUserName(), "今天天气真好!");
    //李莫愁来点赞
    momentsService.likeStatus(statusId,user2.getUserName());
    //周芷若也来点赞
    momentsService.likeStatus(statusId,user3.getUserName());
}
结果:

原理进阶
@EventListener是Spring框架中用于监听事件的注解,它的原理是基于观察者模式实现的。当一个事件被发布时,所有监听该事件的方法都会被调用。在Spring中,事件的发布者是ApplicationEventPublisher接口,它定义了一个publishEvent方法,用于发布事件。当调用publisher.publishEvent(new LikeEvent(statusId, liker))时,会将LikeEvent事件发布出去,所有监听该事件的方法都会被调用。

在处理LikeEvent事件时,Spring会根据方法参数的类型来确定哪些方法可以处理该事件。例如,如果一个方法的参数类型是LikeEvent,那么它就可以处理LikeEvent事件。当有多个方法可以处理同一个事件时,Spring会根据@Order注解或者实现Ordered接口来确定方法的执行顺序。

具体来说,当调用publisher.publishEvent(new LikeEvent(statusId, liker))时,Spring会在容器中查找所有标注了@EventListener注解的方法,并将LikeEvent事件传递给这些方法进行处理。如果一个方法的参数类型与LikeEvent事件匹配,那么它就会被调用。

例如,假设有一个handleLikeEvent方法,它的参数类型是LikeEvent,那么当调用publisher.publishEvent(new LikeEvent(statusId, liker))时,Spring会将LikeEvent事件传递给handleLikeEvent方法进行处理。

总之,@EventListener注解的原理是基于观察者模式实现的,它可以让我们方便地监听和处理事件。当一个事件被发布时,所有监听该事件的方法都会被调用,Spring会根据方法参数的类型来确定哪些方法可以处理该事件。

必须说透
有的同学看到这里会有问题,为什么要用这种事件模式,我在点赞的时候直接调用处理点赞的方法不就行了吗?使用事件模式可以将代码解耦,使得代码更加灵活和可扩展。如果直接调用处理点赞的方法,那么每次需要添加新的功能或者修改现有功能时,都需要修改这个方法,这样会导致代码的耦合度很高,难以维护和扩展。

而使用事件模式,可以将点赞事件和处理点赞的方法分离开来,当有新的功能需要添加时,只需要添加一个新的事件处理器即可,不需要修改原有的代码,这样可以大大提高代码的可维护性和可扩展性。比如,我现在有一个需求,有人点赞后,还要打印动态的点赞总数,是不是只能去修改点赞方法了呢?

可是如果用事件,只需要再一个 @EventListener 即可。
@EventListener
public void handleLikeEvent2(LikeEvent event) {
    String statusId = event.getStatusId();
    Status status = statuses.get(statusId);
    if (status != null) {
        System.out.println("当前点赞总数:" + status.getLikes().size());

    }
}
只需要增加这段代码,其他任何地方都不要动,就是这么爽!
测试结果:

用户评论