1. 使用ApplicationEventPublisher 发布事件
复制下面全部代码,右键包名,粘贴即可生成java类,执行即可看到效果。
事件机制
- 需要自定义一个事件类继承ApplicationEvent;
- 需要自定义一个监听器类实现ApplicationListener接口,或普通类的方法中使用@EventListener注解;
- 使用默认发布器ApplicationEventPublisher发布即可;
- 事件类不需要注入到IOC;监听器需要注入到IOC;ApplicationEventPublisher用Autowired注入进来即可;
- 默认情况下,事件发布与执行是同步的,事件执行完毕,发布者才会执行下面的逻辑;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 | package com.example.controller; import com.alibaba.fastjson.JSON; import com.example.SpringbootRedisApplication; import lombok.Data; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationListener; import org.springframework.context.event.EventListener; import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.stereotype.Component; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import java.util.Objects; @RunWith (SpringJUnit4ClassRunner. class ) @SpringBootTest (classes = SpringbootRedisApplication. class ) @Slf4j @EnableAsync public class PublishEventDemo { /** * 事件机制: * 需要自定义一个事件类继承ApplicationEvent; * 需要自定义一个监听器类实现ApplicationListener接口,或普通类的方法中使用@EventListener注解; * 使用默认发布器ApplicationEventPublisher发布即可; * 事件类不需要注入到IOC;监听器需要注入到IOC;ApplicationEventPublisher用Autowired注入进来即可; */ /** * 事件发布器 */ @Autowired private ApplicationEventPublisher eventPublisher; /** * 测试类 */ @Test public void publishTest() throws InterruptedException { Task task = new Task(); task.setId(1L); task.setTaskName( "测试任务" ); task.setTaskContext( "任务内容" ); task.setFinish( false ); MyEvent event = new MyEvent(task); log.info( "开始发布任务" ); eventPublisher.publishEvent(event); //applicationContext.publishEvent(event); log.info( "结束发布任务" ); Thread.sleep( 10000 ); } } /** * 任务类 * 任务就是一个普通的类,用来保存你要发布事件的内容。这个没有特殊限制,可以根据自己业务随意设置。 */ @Data class Task { private Long id; private String taskName; private String taskContext; private boolean finish; } /** * 事件类 * 事件类需要继承org.springframework.context.ApplicationEvent,这样发布的事件才能被Spring所识别 */ @Slf4j class MyEvent extends ApplicationEvent { private Task task; public MyEvent(Task task) { super (task); this .task = task; } public Task getTask() { return task; } } /** * 事件监听类 * 事件的监听器需要实现org.springframework.context.ApplicationListener,并且需要注入到容器之中。 */ @Component @Slf4j class MyEventListenerA implements ApplicationListener { /** * 监听方式1:实现ApplicationListener接口,重写onApplicationEvent方法 * 需要使用Component注入IOC */ @SneakyThrows @Async @Override public void onApplicationEvent(MyEvent MyEvent) { Thread.sleep( 5000 ); if (Objects.isNull(MyEvent)) { return ; } Task task = MyEvent.getTask(); log.info( "监听器A接收任务:{}" , JSON.toJSONString(task)); task.setFinish( true ); log.info( "监听器A此时完成任务" ); } } @Component @Slf4j class MyEventListenerB implements ApplicationListener { /** * 监听方式2:接口和注解混合使用 * 但此时 @EventListener不能与注解@Async在同一个类中使用,会报错,至于为什么,不知道; * 需要使用Component注入IOC */ //@Async//加上这个,@EventListener的方法就会报java.lang.IllegalStateException: Failed to load ApplicationContext @SneakyThrows @Override public void onApplicationEvent(MyEvent MyEvent) { Thread.sleep( 1000 ); if (Objects.isNull(MyEvent)) { return ; } Task task = MyEvent.getTask(); log.info( "监听器B接收任务:{}" , JSON.toJSONString(task)); task.setFinish( true ); log.info( "监听器B此时完成任务" ); } @EventListener public void someMethod(MyEvent event) throws InterruptedException { Thread.sleep( 1000 ); log.info( "监听器@EventListenerB收到={}" , event.getTask()); } } @Component @Slf4j class MyEventListennerC { /** * 监听方式3:注解@EventListener的监听器不需要实现任何接口 * 需要使用Component注入IOC */ @EventListener public void someMethod(MyEvent event) throws InterruptedException { Thread.sleep( 1000 ); log.info( "监听器@EventListenerC收到={}" , event.getTask()); } } |
运行日志:
2020-11-30 18:13:56.238 INFO 19776 — [ main] com.example.controller.PublishEventDemo : Started PublishEventDemo in 11.098 seconds (JVM running for 13.737)
2020-11-30 18:13:56.902 INFO 19776 — [ main] com.example.controller.PublishEventDemo : 开始发布任务
2020-11-30 18:13:57.904 INFO 19776 — [ main] com.example.controller.MyEventListenerB : 监听器@EventListenerB收到=Task(id=1, taskName=测试任务, taskContext=任务内容, finish=false)
2020-11-30 18:13:58.905 INFO 19776 — [ main] c.example.controller.MyEventListennerC : 监听器@EventListenerC收到=Task(id=1, taskName=测试任务, taskContext=任务内容, finish=false)
2020-11-30 18:13:59.920 INFO 19776 — [ main] com.example.controller.MyEventListenerB : 监听器B接收任务:{“finish”:false,”id”:1,”taskContext”:”任务内容”,”taskName”:”测试任务”}
2020-11-30 18:13:59.921 INFO 19776 — [ main] com.example.controller.MyEventListenerB : 监听器B此时完成任务
2020-11-30 18:13:59.921 INFO 19776 — [ main] com.example.controller.PublishEventDemo : 结束发布任务
2020-11-30 18:14:03.913 INFO 19776 — [ task-1] com.example.controller.MyEventListenerA : 监听器A接收任务:{“finish”:true,”id”:1,”taskContext”:”任务内容”,”taskName”:”测试任务”}
2020-11-30 18:14:03.913 INFO 19776 — [ task-1] com.example.controller.MyEventListenerA : 监听器A此时完成任务
2020-11-30 18:14:09.958 INFO 19776 — [ Thread-3] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService ‘applicationTaskExecutor’
事件发送后,会等待事件执行完毕,因此他们是同步的。若想异步执行事件,可以把@Async加到监听方法上;
2. 使用ApplicationContext发布事件
与上例不同之处
- 使用ApplicationContext发布事件,ApplicationContext实现了ApplicationEventPublisher接口;
- 使用ApplicationContextEvent 定义事件,ApplicationContextEvent 继承了ApplicationEvent类;
demo代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | package com.example.controller; import ch.qos.logback.classic.Logger; import com.example.SpringbootRedisApplication; import lombok.ToString; import lombok.extern.slf4j.Slf4j; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationListener; import org.springframework.context.event.ApplicationContextEvent; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.web.bind.annotation.RestController; @RunWith (SpringJUnit4ClassRunner. class ) @SpringBootTest (classes = SpringbootRedisApplication. class ) @RestController @Slf4j public class PublishEventDemo2 { /** * 使用ApplicationContext发布事件 */ @Autowired ApplicationContext applicationContext; @Test public void send() { MyEvent2 myEvent2 = new MyEvent2(applicationContext); myEvent2.setData( "数据" ); log.info( "开始发送事件" ); applicationContext.publishEvent(myEvent2); log.info( "结束发送事件" ); } } /** * 监听器类 */ @Slf4j @Component class MyEventListener2 implements ApplicationListener { @Override public void onApplicationEvent(MyEvent2 event) { log.info( "监听器MyEventListener2收到={}" , event); } @EventListener public void someMethod(MyEvent2 event) { log.info( "监听器MyEventListener2@EventListener收到={}" , event); } } /** * 监听器类 */ @Slf4j @Component class MyEventListenner1 { @EventListener public void someMethod(MyEvent2 event) { log.info( "监听器MyEventListenner1收到={}" , event); } } /** * 事件类 * * @param */ @ToString class MyEvent2 extends ApplicationContextEvent { private T data; public MyEvent2(ApplicationContext source) { super (source); } public T getData() { return data; } public void setData(T data) { this .data = data; } } |
运行日志:
2020-11-30 18:03:38.638 INFO 15792 — [ main] c.example.controller.PublishEventDemo2 : Started PublishEventDemo2 in 9.571 seconds (JVM running for 12.677)
2020-11-30 18:03:39.355 INFO 15792 — [ main] c.example.controller.PublishEventDemo2 : 开始发送事件
2020-11-30 18:03:39.358 INFO 15792 — [ main] com.example.controller.MyEventListener2 : 监听器MyEventListener2@EventListener收到=MyEvent2(data=数据)
2020-11-30 18:03:39.359 INFO 15792 — [ main] c.example.controller.MyEventListenner1 : 监听器MyEventListenner1收到=MyEvent2(data=数据)
2020-11-30 18:03:39.359 INFO 15792 — [ main] com.example.controller.MyEventListener2 : 监听器MyEventListener2收到=MyEvent2(data=数据)
2020-11-30 18:03:39.359 INFO 15792 — [ main] c.example.controller.PublishEventDemo2 : 结束发送事件
2020-11-30 18:03:39.435 INFO 15792 — [ Thread-3] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService ‘applicationTaskExecutor’
事件发送后,会等待事件执行完毕,因此他们是同步的。若想异步执行事件,可以把@Async加到监听方法上;
以上为个人经验,希望能给大家一个参考,也希望大家多多支持IT俱乐部。