5分钟搞懂spring事件

事件三大概念

1.事件

事件对象,就比如说用户登录、发送邮件、打开QQ都是事件。

2.事件源

产生事件的对象,这个概念是比较抽象的,需要自己去理解,因为它不可能通过一个事件就能明确这个事件的事件源,具体要根据业务逻辑去自行判断,就比如 用户登录 的事件源可能是一个用户实体类,这个用户需要有名称、地点(在哪里登录的)、登录时间…。发送邮件的事件源可能是一个邮件,这个邮件包括邮件地址、邮件内容、发送时间…。具体的怎么定义事件源还需要自己在生产中自己去考虑

3.事件发布器

发送事件的对象,由他将事件发布出去,该事件发出后,只要有相应的事件监听器,该事件就会被监听到。

4.事件监听器

负责监听事件的对象,事件发布器发布相应事件后,被监听器监听到,继而完成相应业务逻辑(注意:业务逻辑就写在监听器里)。

代码具体实现

1.事件

事件类需要继承于ApplicationEvent类,这样才能被事件监听器监听到、被发布器发布。
SendEmail为事件源

public class EmailEvent extends ApplicationEvent {

    private SendEmail email;

    public EmailEvent(SendEmail email) {
        super(email);
        this.email = email;
    }
}
2.事件源

事件源其实就是一个普通的类,或者说是实体类,用来保存你要发布事件的内容,比如本实例中发送邮件的事件源就定为邮件

@Data
@AllArgsConstructor
public class SendEmail {
    /**
     * 发件人姓名
     */
    private String name;
    /**
     * 邮箱地址
     */
    private String email;
    /**
     * 邮件内容
     */
    private String content;
}
3.事件发布器

自定义一个事件发布器,注入ApplicationContext,查看类接口之间的关系:

在这里插入图片描述
我们发现该接口继承于ApplicationEventPublisher接口,所以可以用ApplicationContext发布事件

@Component
public class DemoPublisher {
    @Autowired
    ApplicationContext applicationContext;

    public void publishEmail(EmailEvent event){
        applicationContext.publishEvent(event);
    }
}
4.事件监听器

监听器的实现有两种方式:
1.实现ApplicationListener接口
2.使用@EventListener注解
本例使用注解方式实现

@Component
@Slf4j
public class DemoEventListener {
    @EventListener
    public void onEmailListener(EmailEvent event){
        log.info("监听到了发邮件事件,开始给用户发邮件");
        SendEmail source = (SendEmail) event.getSource();
        log.info("给用户"+source.getName()+"("+source.getEmail()+")发送邮件,内容为:"+source.getContent());
        log.info("发邮件事件完成");
    }
}
5.添加Controller类,启动程序
@RestController
public class MyController {
    private static Logger logger = LoggerFactory.getLogger(MyController.class);
    @Autowired
    DemoPublisher publisher;

    @RequestMapping("/test")
    public String test(){
        SendEmail email = new SendEmail("程大哥","782053943@qq.com","哈哈哈");
        EmailEvent event = new EmailEvent(email);
        logger.info("开始发布事件");
        publisher.publishEmail(event);
        logger.info("结束发布事件");
        return "hello world";
    }
}

在这里插入图片描述
由于spring事件默认是同步的,这样会做的话会阻塞线程的执行,在世纪的生产中,如果发布事件过多,而且还是使用同步的话,对用户的体验是极差的,所以需要我们呢去手动开启异步事件。

6.开启异步事件

只需要在配置类上加上@EnableAsync注解就行了,该注解用于声明启用Spring的异步方法执行功能,需要和@Configuration 注解一起使用,或者我们可以直接加在启动类上。 然后在监听方法上加上@Async注解,说明当前方法使用异步去执行。

@SpringBootApplication
@EnableAsync
public class SpringEventDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringEventDemoApplication.class, args);
    }
}

模拟多个事件(按照以上操作再添加一个打折事件)

@Component
@Slf4j
public class DemoEventListener {
    @EventListener
    @Async
    public void onDiscountListener(DiscountEvent event){
        log.info("监听到了折扣事件,开始给用户折扣");
        Discount source = (Discount) event.getSource();
        log.info("给用户"+source.getDsctName()+"优惠卷金额"+source.getAmount());
        log.info("折扣事件完成");

    }
    @EventListener
    @Async
    public void onEmailListener(EmailEvent event){
        log.info("监听到了发邮件事件,开始给用户发邮件");
        SendEmail source = (SendEmail) event.getSource();
        log.info("给用户"+source.getName()+"("+source.getEmail()+")发送邮件,内容为:"+source.getContent());
        log.info("发邮件事件完成");
    }
}

执行结果(蓝色箭头是aop的东西,不管)
可以看到,直接开始结束,线程并没有出现阻塞,两个事件的逻辑在另外的两个线程完成,这样做用户的响应时间会降低
在这里插入图片描述

注意:如果2个事件之间是继承关系,会先监听到子类事件,处理完再监听父类。

记得点赞评论加关注!!!
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值