ApplicationEvent的应用
事件驱动
事件:就是发生了什么事情,比如支付、扣款、过期等等就会发出通知,告诉相关业务系统发生了这件事
监听:监听相关系统发送的通知,从而做出处理
需求描述:创建订单完毕,需要给客户发送消息,然后缓存用户订单信息。删除订单时,需要按照顺序,先发短信,再清理缓存,再做其他操作
1:定义订单创建的事件源
package com.demo.ddd.event; import com.demo.ddd.entity.Order; import org.springframework.context.ApplicationEvent; /** * 订单事件源*/ public class OrderEvent extends ApplicationEvent { private Order order; public Order getOrder() { return order; } public void setOrder(Order order) { this.order = order; } public OrderEvent(Object source) { super(source); } public OrderEvent(Object source, Order order) { super(source); this.order = order; } }
2:创建订单生成监听类
创建的时候使用异步的方式,在主类上增加@EnableAsync,在方法上增加@Async 就实现了异步
package com.demo.ddd.event; import lombok.extern.slf4j.Slf4j; import org.springframework.context.event.EventListener; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; /** * 事件订阅处理 注解方式 **/ @Component @Slf4j public class EventHandler { @EventListener(OrderEvent.class) //监听的事件源类 @Async //异步 public void orderStart(OrderEvent orderEvent) { // TODO 给客户发送短信逻辑 System.out.println(Thread.currentThread().getName() + "发送短信提醒客户完毕!客户信息:" + orderEvent.getOrder().getCustomerDTO()); } @EventListener(OrderEvent.class) @Async //异步 public void orderEvent(OrderEvent orderEvent) { // TODO 订单缓存逻辑 System.out.println(Thread.currentThread().getName() + "订单缓存完毕!客户信息:" + orderEvent.getOrder().getCustomerDTO()); } }
3:创建删除订单事件源
package com.demo.ddd.event; import com.demo.ddd.entity.Order; import org.springframework.context.ApplicationEvent; /** * 订单删除事件源*/ public class OrderRemoveEvent extends ApplicationEvent { private Order order; public Order getOrder() { return order; } public void setOrder(Order order) { this.order = order; } public OrderRemoveEvent(Object source) { super(source); } public OrderRemoveEvent(Object source, Order order) { super(source); this.order = order; } }
4:创建订单删除事件监听
删除事件 采用另一种继承的方式实现
package com.demo.ddd.event; import org.springframework.context.ApplicationListener; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; /** * 控制顺序的继承方式 **/ @Component @Order(1) //数字越小,越优先执行 public class OrderRemoveEventHandler implements ApplicationListener<OrderRemoveEvent> { //泛型里是监听的事件源类 @Override public void onApplicationEvent(OrderRemoveEvent event) { System.out.println(Thread.currentThread().getName() + "删除订单事件第一步!发送短信:" + event.getOrder()); } } @Component @Order(2) class OrderRemoveCache implements ApplicationListener<OrderRemoveEvent> { @Override public void onApplicationEvent(OrderRemoveEvent event) { System.out.println(Thread.currentThread().getName() + "删除订单事件第二步!清理缓存:" + event.getOrder()); } } @Component @Order(3) class OrderRemove implements ApplicationListener<OrderRemoveEvent> { @Override public void onApplicationEvent(OrderRemoveEvent event) { System.out.println(Thread.currentThread().getName() + "删除订单事件第三步!其他处理:" + event.getOrder()); } }
5:发布事件
package com.demo.ddd; import com.demo.base.BaseContextService; import com.demo.context.OrderContext; import com.demo.ddd.entity.Order; import com.demo.ddd.event.OrderEvent; import com.demo.ddd.event.OrderRemoveEvent; import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Service; /** *订单业务*/ @Service public class OrderApplicationService { private ApplicationContext applicationContext; public OrderApplicationService(ApplicationContext applicationContext) { this.applicationContext = applicationContext; } public boolean save(OrderDTO orderDTO) { // TODO 1:保存订单// 2:发送消息 applicationContext.publishEvent(new OrderEvent(this, cover)); return true; } public boolean remove(OrderDTO orderDTO) { // TODO 1:删除订单// 2:发送消息 applicationContext.publishEvent(new OrderRemoveEvent(this, cover)); return true; } }
6:访问测试
这是一个springboot工程,其他都很简单,就不贴代码了
点击保存
控制台打印信息
点击删除
控制台打印
原理
1:通过断点先进入publishEvent方法
2:进入下一步到达这个位置
3:从一个bean集合中取出对应的Listener
4:拿到目标以后
循环执行
5:最后执行的这个方法的
6:看到这里就明白了 通过观察者模式,在发布的时候,根据类型去retrieverCache 缓存查找响应的Listener,然后执行onApplicationEvent方法,而这个方法 正是我们监听重写的方法,注解模式虽然我们定义的名字不一样,但是注解底层最终也是通过ApplicationListener对我们的方法进行实现的。需要注意的是,我们第一次系统启动时,我们自定义的监听类是不会被缓存起来的,所以在处理一些底层细节上,需要留意这一点,如果有特殊需要,则需要再系统启动之初,在代码级别自动触发一次,它就能缓存起来。具体逻辑可以参考下图: