开发者社区> 李烈火> 正文

Spring事件摸摸摸

简介: Spring事件是什么?如何使用才能满足我的需求,这里就来讲解Spring事件的用法和特性。
+关注继续查看

Spring事件

概述

Spring事件是Spring Framework中观察者模式的体现,其主要应用于ApplicationContext生命周期中各关键点的通知。

文档:https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/htmlsingle/#context-functionality-events

文档中有一段特别说明,大概的意思就是从4.2版本开始事件得到了巨大的升级,加入了基于注解的使用方式和用任意对象作为事件,下面都会进行讲解。

As of Spring 4.2, the event infrastructure has been significantly improved and offers an annotation-based model as well as the ability to publish any arbitrary event (that is, an object that does not necessarily extend from ApplicationEvent). When such an object is published, we wrap it in an event for you.


分类

从文档章节标题来看,事件分为标准事件和自定义事件。标准事件就是Spring内置的事件,下图就是Spring Framework中的标准事件;自定义事件就是用户利用框架事件机制创建的事件。

image.png

原始用法

最早的实现方式是继承和实现对应的接口,主要包括ApplicationEventApplicationEventPublisherAwareApplicationListener

1. 定义事件

事件需要继承ApplicationEvent,事件中包含了你需要传递的数据

public class BlockedListEvent extends ApplicationEvent {

    private final String address;
    private final String content;

    public BlockedListEvent(Object source, String address, String content) {
        super(source);
        this.address = address;
        this.content = content;
    }

    // accessor and other methods...
}

2. 创建事件监听

监听要实现ApplicationListener接口,实现接收事件方法onApplicationEvent(evetn)

public class BlockedListNotifier implements ApplicationListener<BlockedListEvent> {

    private String notificationAddress;

    public void setNotificationAddress(String notificationAddress) {
        this.notificationAddress = notificationAddress;
    }

    public void onApplicationEvent(BlockedListEvent event) {
        // 处理收到的事件
    }
}

3. 发布事件

发布事件使用框架内的ApplicationEventPublisher实现类的实例。由于ApplicationContext也实现了该接口,所以用ApplicationContext也可以发布事件,代码applicationContext.publishEvent(event)

public class EmailService implements ApplicationEventPublisherAware {

    private List<String> blockedList;
    private ApplicationEventPublisher publisher;

    public void setBlockedList(List<String> blockedList) {
        this.blockedList = blockedList;
    }

    public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
        this.publisher = publisher;
    }

    public void sendEmail(String address, String content) {
        if (blockedList.contains(address)) {
            publisher.publishEvent(new BlockedListEvent(this, address, content));
            return;
        }
        // send email...
    }
}

4. 总结

这是最原始的使用方式,由于Java是单继承,这样会产生很大的限制,而且继承和实现也会导致框架的侵入性


用注解优化Listener

作为上一种使用方式的升级,注解的加入不但减少了框架的侵入还支持了监听多个事件甚至做到了按条件监听事件

// 基本用法
public class BlockedListNotifier {

    @EventListener
    public void processBlockedListEvent(BlockedListEvent event) {
        // notify appropriate parties via notificationAddress...
    }
}
// 监听多个事件,但注意方法参数
@EventListener({ContextStartedEvent.class, ContextRefreshedEvent.class})
public void handleContextStart() {
    // ...
}
// 按特定条件接收事件,具体用法见官方文档
@EventListener(condition = "#blEvent.content == 'my-event'")
public void processBlockedListEvent(BlockedListEvent blEvent) {
    // notify appropriate parties via notificationAddress...
}
// 接收事件后发布另一个事件,注意返回值,甚至你可以返回一批事件。另外,文档中特别注明异步事件不支持
@EventListener
public ListUpdateEvent handleBlockedListEvent(BlockedListEvent event) {
    // notify appropriate parties via notificationAddress and
    // then publish a ListUpdateEvent...
}
//

异步事件

默认情况下,Listener是同步处理事件的,你可以理解为发布事件的方法同步调用处理事件的方法。但通常情况是希望是异步调用。那么实现方式是使用@Async注解。

@EventListener
@Async
public void processBlockedListEvent(BlockedListEvent event) {
    // BlockedListEvent is processed in a separate thread
}


最后说明一下,异步事件中,Listener抛出的异常不会传递到发布方。也无法通过返回值来发布新的事件。


循序监听

当有多个监听器监听同一个事件且需要指定监听的顺序时,需要使用@Order指定。

@EventListener
@Order(42)
public void processBlockedListEvent(BlockedListEvent event) {
    // notify appropriate parties via notificationAddress...
}


通过泛型限定监听范围

通过对事件增加泛型,可以控制监听器监听的事件范围

@EventListener
public void onPersonCreated(EntityCreatedEvent<Person> event) {
    // ...
}

如上,当需要定义一个非固定类型的泛型事件时,可以用下面的方式

public class EntityCreatedEvent<T> extends ApplicationEvent implements ResolvableTypeProvider {

    public EntityCreatedEvent(T entity) {
        super(entity);
    }

    @Override
    public ResolvableType getResolvableType() {
        return ResolvableType.forClassWithGenerics(getClass(), ResolvableType.forInstance(getSource()));
    }
}

使用任意类型作为事件

原始用法中说到,作为单继承的语言,事件继承ApplicationEvent会产生很多限制。而Spring框架也在4.2进行了升级,任意的对象都可以作为一个事件发布出去,也就是说事件不必继承ApplicationEvent,普通的Java Bean就可以作为事件。

public class BlockedListEvent {

    private final String address;
    private final String content;

    public BlockedListEvent(String address, String content) {
        this.address = address;
        this.content = content;
    }

    // accessor and other methods...
}

ApplicationEventPublisher也有对应的发布方法

image.png











版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
精通SpringBoot——第四篇:Spring事件 Application Event
SpringBoot 实现事件 Application Event的发布和监听。
2719 0
Spring 事务提交成功事件监听
现在微服务做得越来越多了,头就越来月疼了。 跨系统事务和跨系统分页是最头疼的(其实头疼也没用,解决不了的问题)   现在有这么个需求(其实同样的需求见到不少了,一直没解决): 向数据库插入记录,并把数据发MQ给其他系统消费。
1897 0
阿里云ECS云服务器初始化设置教程方法
阿里云ECS云服务器初始化是指将云服务器系统恢复到最初状态的过程,阿里云的服务器初始化是通过更换系统盘来实现的,是免费的,阿里云百科网分享服务器初始化教程: 服务器初始化教程方法 本文的服务器初始化是指将ECS云服务器系统恢复到最初状态,服务器中的数据也会被清空,所以初始化之前一定要先备份好。
14585 0
Spring 4.2框架中注释驱动的事件监听器详解
版权声明:本文为博主chszs的原创文章,未经博主允许不得转载。 https://blog.csdn.net/chszs/article/details/49097919 Spring 4.2框架中注释驱动的事件监听器详解 作者:chszs,版权所有,未经同意,不得转载。
926 0
阿里云ECS云服务器初始化设置教程方法
阿里云ECS云服务器初始化是指将云服务器系统恢复到最初状态的过程,阿里云的服务器初始化是通过更换系统盘来实现的,是免费的,阿里云百科网分享服务器初始化教程: 服务器初始化教程方法 本文的服务器初始化是指将ECS云服务器系统恢复到最初状态,服务器中的数据也会被清空,所以初始化之前一定要先备份好。
13743 0
阿里云服务器端口号设置
阿里云服务器初级使用者可能面临的问题之一. 使用tomcat或者其他服务器软件设置端口号后,比如 一些不是默认的, mysql的 3306, mssql的1433,有时候打不开网页, 原因是没有在ecs安全组去设置这个端口号. 解决: 点击ecs下网络和安全下的安全组 在弹出的安全组中,如果没有就新建安全组,然后点击配置规则 最后如上图点击添加...或快速创建.   have fun!  将编程看作是一门艺术,而不单单是个技术。
17893 0
如何通过审计安全事件日志检测密码喷洒(Password Spraying)攻击
许多渗透测试人员和攻击者通常都会使用一种被称为“密码喷洒(Password Spraying)”的技术来进行测试和攻击。对密码进行喷洒式的攻击,这个叫法很形象,因为它属于自动化密码猜测的一种。这种针对所有用户的自动密码猜测通常是为了避免帐户被锁定,因为针对同一个用户的连续密码猜测会导致帐户被锁定。
1229 0
阿里云服务器怎么设置密码?怎么停机?怎么重启服务器?
如果在创建实例时没有设置密码,或者密码丢失,您可以在控制台上重新设置实例的登录密码。本文仅描述如何在 ECS 管理控制台上修改实例登录密码。
19579 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,大概有三种登录方式:
8935 0
+关注
4
文章
169
问答
文章排行榜
最热
最新
相关电子书
更多
OceanBase 入门到实战教程
立即下载
阿里云图数据库GDB,加速开启“图智”未来.ppt
立即下载
实时数仓Hologres技术实战一本通2.0版(下)
立即下载