ApplicationEvent与ApplicationListener

前言:

    Spring的世界中有这么一对好基友,两个人总是同时出现,相爱相杀。这就是ApplicationEvent与ApplicationListener。感觉有点像小偷和警察,只要ApplicationEvent一出现,ApplicationListener就会发现TA。

    下面我们就来看一个示例,是Spring官方文档提供的示例。

    笔者大概说明一下这个示例的背景:就是一个发送邮件的功能,如果在发送邮件的过程中,发现邮件地址在黑名单内,那么就发送一个黑名单事件,负责监听该事件的Listener就会监听到,打印相关信息;如果不在黑名单内,就直接发送出去。

    下面就先看下官网提供的示例吧

1.发送邮件的黑名单事件与监听

    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("[email protected]","[email protected]","[email protected]","[email protected]"));

        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("[email protected]", "content");// 在黑名单内部
        emailService.sendEmail("[email protected]", "content");// 不在黑名单内部
    }
}

// res
[email protected]已被列入黑名单,不能发送邮件
[email protected]邮件已被发送...

    总结:从结果可以看出,在黑名单内部的邮箱触发了Event,并且被Listener监听到,而正常的邮箱地址则不会。

    以上就是Event与Listener的一个简单示例(来自官网)。

    那下面我们从示例倒推,我们能用Event和Listener做什么呢?哪些场景比较适合用这个组合呢?

2.Event和Listener简析

    仔细看下,会有一种熟悉的感觉,这不就是我们的观察者模式嘛

    对的,就是观察者模式,设计的初衷就是为了业务系统之间的解耦,提高可扩展性和可维护性。

    就像我们在使用MQ发送消息接收消息的时候,发送者并不关心谁来接收消息,只关心消息是否能发送出去,而接收者也并不关心消息从哪里被发送过来,只需要在接收到消息之后进行处理即可。

    所以,我们完全可以当MQ的心态来使用,如果我们希望两个事件完全解耦,两者之间不要有任何直接的联系,那么就可以考虑使用Event和Listener

3.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来标记处理顺序

4.Spring提供的事件列表

    来自于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  

发布了122 篇原创文章 · 获赞 119 · 访问量 12万+

猜你喜欢

转载自blog.csdn.net/qq_26323323/article/details/94839163