Java中事件监听 ¶
应用场景 ¶
案例 ¶
假设现在有这么一个业务场景:
用户在京西商城下单成功后,平台要发送短信通知用户下单成功
最直观的想法是直接在order()方法中添加发送短信的业务代码:
java
1public void order(){
2 // 下单成功
3 System.out.println("下单成功...");
4 // 发送短信
5 sendSms();
6}乍一看没什么不妥,但是如果我们加上一根时间轴,那么代码就有问题了:
一个月后,京西搞了自建物流体系,用户下单成功后,需要通知物流系统发货
于是你又要打开OrderService修改order()方法:
java
1public void order(){
2 // 下单成功
3 System.out.println("下单成功...");
4 // 发送短信
5 sendSms();
6 // 通知车队发货
7 notifyCar();
8}又过了一个月,东哥被抓了,股价暴跌,决定卖掉自己的车队,所以下单后就不用通知车队了
重新修改OrderService:
java
1public void order(){
2 // 下单成功
3 System.out.println("下单成功...");
4 // 发送短信
5 sendSms();
6 // 车队没了,注释掉这行代码
7 // notifyCar();
8}又过了一个月,东哥明尼苏达州荣耀归来:回来做我的兄弟一起开车吧。
好的,东哥。
java
1public void order(){
2 // 下单成功
3 System.out.println("下单成功...");
4 // 发送短信
5 sendSms();
6 // 车队买回来了
7 notifyCar()
8}车队回来了,你却受不了这大起大落异常刺激的生活,决定离职
以增量的方式应对变化的需求 ¶

Spring事件监听 ¶
业务代码 ¶
java
1/**
2 * 订单服务
3 */
4@Service
5public class OrderService {
6
7 @Autowired
8 private ApplicationContext applicationContext;
9
10 public void order() {
11 // 下单成功
12 System.out.println("下单成功...");
13 // 发布通知
14 applicationContext.publishEvent(new OrderSuccessEvent(this));
15 System.out.println("main线程结束...");
16 }
17}自定义事件 ¶
OrderSuccessEvent(继承ApplicationEvent,自定义事件)
java
1public class OrderSuccessEvent extends ApplicationEvent {
2 //这里还可以自定义参数,并通过构造方法赋值
3 public OrderSuccessEvent(Object source) {
4 super(source);
5 }
6}监听事件 ¶
可以指定监听者监听的事件类型,那么就会对未声明的事件不进行监听
SmsService(实现ApplicationListener,监听OrderSuccessEvent)
java
1/**
2 * 短信服务,监听OrderSuccessEvent
3 */
4@Service
5public class SmsService implements ApplicationListener<OrderSuccessEvent> {
6
7 @Override
8 public void onApplicationEvent(OrderSuccessEvent event) {
9 this.sendSms();
10 }
11
12 /**
13 * 发送短信
14 */
15 public void sendSms()
16 System.out.println("发送短信...");
17 }
18}也可以通过注解的方式监听事件
java
1@EventListener(classes = OrderSuccessEvent.class)
2public void onApplicationEvent(OrderSuccessEvent event) {
3 System.out.println("发送短信...");
4}Test ¶
java
1@RunWith(SpringRunner.class)
2@SpringBootTest
3public class Test {
4
5 @Autowired
6 private OrderService orderService;
7
8 @Test
9 public void testSpringEvent() {
10 orderService.order();
11 }
12}
13
14//输出
15// 下单成功...
16// 发送短信...
17// main线程结束...异步调用 ¶
某些时候,为了推送第三方信息的执行不影响业务代码,可以通过在监听事件的方法上添加注解@Async注解,开启异步执行(启动类需要配置注解:@EnableAsync)
事务监听 ¶
对于业务代码需要提交事务后,或者说等待主线程执行完毕后再推送第三方信息,则可以使用事务监听
和普通事件监听类似,先定义事件,其次再定义事件监听器,事件监听器的代码如下
java
1// phase 指定事务什么情况下执行该监听器
2// classes 指定事件
3@Async
4@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT,classes = MyApplicationEvent.class)
5public void onApplicationEventLister(MyApplicationEvent event) {
6 System.out.println("时间监听器B 收到事件:" + event);
7}示例 ¶
创建事件抽象类,以及其实现
java1//事件抽象类 2public abstract class TestEvent extends ApplicationEvent { 3 private static final long serialVersionUID = -7558477450921553407L; 4 private String listenerType; 5 private String msgTwo; 6 7 protected TestEvent(Object source) { 8 super(source); 9 } 10 11 protected TestEvent(Object source, Clock clock) { 12 super(source, clock); 13 } 14 15 public String getListenerType() {return listenerType;} 16 17 public void setListenerType(String listenerType) {this.listenerType = listenerType;} 18 19 public String getMsgTwo() {return msgTwo;} 20 21 public void setMsgTwo(String msgTwo) {this.msgTwo = msgTwo;} 22} 23 24 25//事件实现类,事件T 26public class EventT extends TestEvent{ 27 private static final long serialVersionUID = -3817485810073854944L; 28 private String mineMsg; 29 public EventT(String listenerType,Object source, String mineMsg) { 30 super(source); 31 super.setListenerType(listenerType); 32 this.mineMsg=mineMsg; 33 } 34 35 public String getMineMsg() {return mineMsg;} 36 37 public void setMineMsg(String mineMsg) {this.mineMsg = mineMsg;} 38}创建事件监听抽象类,以及其实现
java1//事件监听器抽象类,也可通过注解,不实现ApplicationListener接口 2public abstract class TestEventListener implements ApplicationListener<TestEvent> { 3 @Override 4 public void onApplicationEvent(TestEvent event) { 5 if (event.getSource() instanceof String) { 6 handleBusinessData(event); 7 } else { 8 throw new IllegalArgumentException("事件类型代码错误"); 9 } 10 } 11 protected abstract void handleBusinessData(TestEvent event); 12 13 //通过注解实现事件监听,而不实现ApplicationListener接口 14/* @Async 15 @EventListener(TestEvent.class) 16 public void onApplicationEvent(TestEvent event) { 17 if (event.getSource() instanceof String) { 18 handleBusinessData(event); 19 } else { 20 throw new IllegalArgumentException("事件类型代码错误"); 21 } 22 }*/ 23} 24 25//事件监听器A实现类,可以根据source与ListenerType对多个不同事件处理不同处理逻辑 26@Component 27public class EventListenerA extends TestEventListener{ 28 @Override 29 protected void handleBusinessData(TestEvent event) { 30 if (!"listenerA".equals(event.getListenerType())) { 31 return; 32 } 33 String code= (String) event.getSource(); 34 switch (code){ 35 case "EventT": 36 System.out.println("EventT"); 37 break; 38 default: 39 throw new RuntimeException("未实现的事件方法"); 40 } 41 } 42}事件发布
java1//事件发布工具类,实现ApplicationContextAware接口,会自动注入ApplicationContext 2@Component 3public class PubEventUtil implements ApplicationContextAware { 4 private static ApplicationContext applicationContext; 5 @Override 6 public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 7 PubEventUtil.applicationContext=applicationContext; 8 } 9 public static void pubEvent(ApplicationEvent event){ 10 applicationContext.publishEvent(event); 11 } 12} 13 14//发布事件 15TestEvent eventT = new EventT("listenerA","EventT", "msg"); 16PubEventUtil.publishEvent(eventT);