SpringBoot事件驱动开发

应用启动过程生命周期事件感知(9大事件)、应用运行中事件感知(无数种)

  • 事件发布:ApplicationEventPublisherAware或注入:ApplicationEventMulticaster
  • 事件监听:组件 + @EventListener

场景:

当用户登录后,我们需要为用户增加一个积分随机获取一张优惠券增加日志等,传统的开发模式为在用户登录的login()方法后调用积分优惠券日志服务。这样在后续的开发中login()方法可能会频繁变动,根据设计模式方法应该对新增开放,修改关闭,所以可以在login()方法中发布登录成功的事件,在积分优惠券日志服务增加对事件的监听进行后续处理即可。

编写代码

LoginController.java

在login()方法后发布登录成功事件

package com.atguigu.boot3.core.controller;

import com.atguigu.boot3.core.entity.UserEntity;
import com.atguigu.boot3.core.event.EventPublisher;
import com.atguigu.boot3.core.event.LoginSuccessEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * @date 2023/10/30 18:57
 */
@RestController
public class LoginController {

    @Autowired
    EventPublisher eventPublisher;

    @GetMapping("/login")
    public String login(@RequestParam("username") String username,
                        @RequestParam("passwd")String passwd){
        //业务处理登录
        System.out.println("业务处理登录完成....");
        
        //1、创建事件信息
        LoginSuccessEvent event = new LoginSuccessEvent(new UserEntity(username, passwd));
        //2、发送事件
        eventPublisher.publishEvent(event);

        //设计模式:对新增开放,对修改关闭
        return username+"登录成功";
    }
}

LoginSuccessEvent.java 事件定义

通过继承ApplicationEvent类,将source传给父类对象。

package com.atguigu.boot3.core.event;

import com.atguigu.boot3.core.entity.UserEntity;
import org.springframework.context.ApplicationEvent;

/**
 * 登录成功事件
 * @author 朱俊伟
 * @date 2023/10/30 18:56
 */
public class LoginSuccessEvent  extends ApplicationEvent {

    /**
     * @param source  代表是谁登录成了
     */
    public LoginSuccessEvent(UserEntity source) {
        super(source);
    }
}

EventPublisher.java事件发布器

定义事件发布器,实现ApplicationEventPublisherAware接口,用来发布事件

package com.atguigu.boot3.core.event;

import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Component;

/**
 * @date 2023/10/30 18:58
 */
@Component
public class EventPublisher implements ApplicationEventPublisherAware {

    /**
     * 底层发送事件用的组件,SpringBoot会通过ApplicationEventPublisherAware接口自动注入给我们
     * 事件是广播出去的。所有监听这个事件的监听器都可以收到
     */
    ApplicationEventPublisher applicationEventPublisher;

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.applicationEventPublisher = applicationEventPublisher;
    }

    /**
     * 发布事件
     * @param event 事件
     */
    public void publishEvent(LoginSuccessEvent event) {
        applicationEventPublisher.publishEvent(event);
    }
}

CouponService.java 优惠券服务

可以通过给方法定义@EventListener注解,代表该类监听某种事件
可以给监听器使用@Order(1)注解定义监听器的顺序,数字越小,越先执行

package com.atguigu.boot3.core.service;

import com.atguigu.boot3.core.entity.UserEntity;
import com.atguigu.boot3.core.event.LoginSuccessEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Service;

/**
 * 优惠券服务
 * @date 2023/10/30 19:06
 */
@Service
@Slf4j
public class CouponService {

    @Order(1)
    @EventListener
    public void onEvent(LoginSuccessEvent loginSuccessEvent){
        log.info("CouponService.onEvent....");
        UserEntity user = (UserEntity) loginSuccessEvent.getSource();
        sendCoupon(user);
    }

    public void sendCoupon(String username){
        System.out.println(username + " 随机得到了一张优惠券");
    }

    public void sendCoupon(UserEntity user){
        sendCoupon(user.getUsername());
    }
}

AccountService.java 积分服务

可以实现ApplicationListener接口来监听事件
实现onApplicationEvent方法来进行事件的处理

package com.atguigu.boot3.core.service;

import com.atguigu.boot3.core.entity.UserEntity;
import com.atguigu.boot3.core.event.LoginSuccessEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationListener;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Service;

/**
 * 积分服务
 * @date 2023/10/30 19:03
 */
@Service
@Slf4j
@Order(2)
public class AccountService implements ApplicationListener<LoginSuccessEvent> {

    @Override
    public void onApplicationEvent(LoginSuccessEvent event) {
      log.info("AccountService.onApplicationEvent.....");
        UserEntity user = (UserEntity) event.getSource();
        addAccountScore(user);
    }

    public void addAccountScore(UserEntity user){
        System.out.println(user.getUsername() +" 加了1分");
    }

}

SysService.java 日志服务

package com.atguigu.boot3.core.service;

import com.atguigu.boot3.core.entity.UserEntity;
import com.atguigu.boot3.core.event.LoginSuccessEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Service;

/**
 * 日志服务
 * @date 2023/10/30 19:09
 */
@Service
@Slf4j
public class SysService {

    @EventListener
    @Order(3)
    public void onEvent(LoginSuccessEvent event){
        log.info("SysService.onEvent....");
        UserEntity user = (UserEntity) event.getSource();
        recordLog(user);
    }

    public void recordLog(UserEntity user){
        System.out.println(user.getUsername() + "登录信息已被记录");
    }
}

UserEntity.java实体类

package com.atguigu.boot3.core.entity;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @date 2023/10/30 18:55
 */
@AllArgsConstructor
@NoArgsConstructor
@Data
@Builder
public class UserEntity {

    private String username;
    private String passwd;
}

调用

http://localhost:8080/login?username=admin&passwd=123

控制台打印结果

业务处理登录完成....
2023-10-30T19:20:11.670+08:00  INFO 11984 --- [nio-8080-exec-5] c.a.boot3.core.service.CouponService     : CouponService.onEvent....
admin 随机得到了一张优惠券
2023-10-30T19:20:11.671+08:00  INFO 11984 --- [nio-8080-exec-5] c.a.boot3.core.service.AccountService    : AccountService.onApplicationEvent.....
admin 加了1分
2023-10-30T19:20:11.671+08:00  INFO 11984 --- [nio-8080-exec-5] c.atguigu.boot3.core.service.SysService  : SysService.onEvent....
admin登录信息已被记录

在业务类中增加方法来实现对事件的监听个人感觉是比较好的方法,可以更好的调节事件处理的顺序以及减少业务类对实现接口的定义。

参考:

https://www.yuque.com/leifengyang/springboot3/lliphvul8b19pqxp#Cq1vD

posted @ 2023-10-30 19:46  雨中遐想  阅读(176)  评论(0编辑  收藏  举报