赞
踩
Spring的世界中有这么一对好基友,两个人总是同时出现,相爱相杀。这就是ApplicationEvent与ApplicationListener。感觉有点像小偷和警察,只要ApplicationEvent一出现,ApplicationListener就会发现TA。
下面我们就来看一个示例,是Spring官方文档提供的示例。
笔者大概说明一下这个示例的背景:就是一个发送邮件的功能,如果在发送邮件的过程中,发现邮件地址在黑名单内,那么就发送一个黑名单事件,负责监听该事件的Listener就会监听到,打印相关信息;如果不在黑名单内,就直接发送出去。
下面就先看下官网提供的示例吧
1)创建事件BlackListEvent
- public class BlackListEvent extends ApplicationEvent {
-
- private final String address;
- private final String content;
-
- public BlackListEvent(Object source, String address, String content) {
- super(source);
- this.address = address;
- this.content = content;
- }
-
- public String getAddress() {
- return address;
- }
-
- public String getContent() {
- return content;
- }
-
-
- // accessor and other methods...
- }
2)创建发送事件器
- public class EmailService implements ApplicationEventPublisherAware {
-
- private List<String> blackList;
- private ApplicationEventPublisher publisher;
-
- public void setBlackList(List<String> blackList) {
- this.blackList = blackList;
- }
-
- @Override
- public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
- this.publisher = publisher;
- }
-
- // 主要逻辑就在这里,发送邮件之前先做一次判断,判断是否在黑名单内
- public void sendEmail(String address, String content) {
- if (blackList.contains(address)) {
- publisher.publishEvent(new BlackListEvent(this, address, content));
- return;
- }
- // send email...
- System.out.println(address + "邮件已被发送...");
- }
- }
3)创建事件监听器
- package eventListener;
- import org.springframework.context.ApplicationListener;
- import org.springframework.stereotype.Component;
-
- public class BlackListNotifier implements ApplicationListener<BlackListEvent> {
-
- @Override
- public void onApplicationEvent(BlackListEvent event) {
- System.out.println(event.getAddress() + "已被列入黑名单,不能发送邮件");
- }
- }
经过上面三步,事件、事件发送器、事件监听器都创建完毕。下面开始测试
4)创建Configuration,封装具体的Bean
- @Configuration
- public class ListenerConfig {
-
- @Bean
- public EmailService emailService(){
-
- EmailService emailService = new EmailService();
- // 在这里添加黑名单集合
- emailService.setBlackList(Arrays.asList("known.spammer@example.org","known.hacker@example.org","john.doe@example.org","blackAddredd@123.com"));
-
- return emailService;
- }
-
- @Bean
- public BlackListNotifier blackListNotifier(){
- return new BlackListNotifier();
- }
- }
5)测试类
- public class ListenerTest {
- @Test
- public void listener() {
- AnnotationConfigApplicationContext applicationContext
- = new AnnotationConfigApplicationContext(ListenerConfig.class);
-
- EmailService emailService = applicationContext.getBean(EmailService.class);
- emailService.sendEmail("blackAddredd@123.com", "content");// 在黑名单内部
- emailService.sendEmail("normalAddr@123.com", "content");// 不在黑名单内部
- }
- }
-
- // res
- blackAddredd@123.com已被列入黑名单,不能发送邮件
- normalAddr@123.com邮件已被发送...
总结:从结果可以看出,在黑名单内部的邮箱触发了Event,并且被Listener监听到,而正常的邮箱地址则不会。
以上就是Event与Listener的一个简单示例(来自官网)。
那下面我们从示例倒推,我们能用Event和Listener做什么呢?哪些场景比较适合用这个组合呢?
仔细看下,会有一种熟悉的感觉,这不就是我们的观察者模式嘛
对的,就是观察者模式,设计的初衷就是为了业务系统之间的解耦,提高可扩展性和可维护性。
就像我们在使用MQ发送消息接收消息的时候,发送者并不关心谁来接收消息,只关心消息是否能发送出去,而接收者也并不关心消息从哪里被发送过来,只需要在接收到消息之后进行处理即可。
所以,我们完全可以当MQ的心态来使用,如果我们希望两个事件完全解耦,两者之间不要有任何直接的联系,那么就可以考虑使用Event和Listener
Spring官网为我们展示了更多的监听器用法。笔者就在这里简单列一下
1)Annotation用法
- public class BlackListNotifierAnnotation {
-
- @EventListener
- public void processBlackListEvent(BlackListEvent event) {
- System.out.println(event.getAddress() + "已被列入黑名单,不能发送邮件");
- }
- }
Spring的强大之处就在于,基本所有的配置都可以用Annotation来代替
我们在开发之中,也可以多用Annotation,代码更简洁
2)异步监听处理
- public class BlackListNotifierAnnotation {
-
- @EventListener
- @Async
- public void processBlackListEvent(BlackListEvent event) {
- System.out.println(event.getAddress() + "已被列入黑名单,不能发送邮件");
- }
- }
如果我们希望监听器的处理是异步的,那么可以考虑使用@Async来处理
3)多Listener
- public class BlackListNotifierAnnotation1 {
-
- @EventListener
- @Order(1)
- public void processBlackListEvent(BlackListEvent event) {
- // 处理事件1...
- doSomething1();
- }
- }
-
- public class BlackListNotifierAnnotation2 {
-
- @EventListener
- @Order(2)
- public void processBlackListEvent(BlackListEvent event) {
- // 处理事件2...
- doSomething2();
- }
- }
这里需要注意下,我们的监听器不是说只能有一个,可以有多个,假如一个事件,在被触发后,处理流程比较长,设计到多个系统,那么可以考虑使用多监听器,每个监听器处理一部分事情。
如果在意监听器的处理顺序,可以使用@Order来标记处理顺序
来自于https://www.jianshu.com/p/ef2cee8c5dd1
序号 | Spring 内置事件 & 描述 |
---|---|
1 | ContextRefreshedEvent ApplicationContext 被初始化或刷新时,该事件被发布。这也可以在 ConfigurableApplicationContext 接口中使用 refresh() 方法来发生。 |
2 | ContextStartedEvent当使用 ConfigurableApplicationContext 接口中的 start() 方法启动 ApplicationContext 时,该事件被发布。你可以调查你的数据库,或者你可以在接受到这个事件后重启任何停止的应用程序。 |
3 | ContextStoppedEvent当使用 ConfigurableApplicationContext 接口中的 stop() 方法停止 ApplicationContext 时,发布这个事件。你可以在接受到这个事件后做必要的清理的工作。 |
4 | ContextClosedEvent当使用 ConfigurableApplicationContext 接口中的 close() 方法关闭 ApplicationContext 时,该事件被发布。一个已关闭的上下文到达生命周期末端;它不能被刷新或重启。 |
5 | RequestHandledEvent这是一个 web-specific 事件,告诉所有 bean HTTP 请求已经被服务。 |
https://docs.spring.io/spring/docs/4.3.23.RELEASE/spring-framework-reference/htmlsingle/
代码地址:https://github.com/kldwz/springstudy
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。