spring的ApplicationEvent事件监听机制原理与应用

spring的ApplicationEvent事件通知机制原理与应用

spring框架抽象出了一套事件机制,通过发布,订阅方式来实现,类似观察者模式。先来搭建一个基本的spring环境,然后做个简单的案例演示事件的应用,最后在做源码分析。

1.环境搭建

引入依赖

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-beans</artifactId>
    <version>5.2.10.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.10.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-support</artifactId>
    <version>5.2.10.RELEASE</version>
</dependency>

创建一个配置类和启动类

@Configuration
public class AppConfig {
   

}

public class TestSpring {
   

    public static void main(String[] args) {
   

        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
    }
}

简单的环境搭建完毕。

2.案例演示

熟悉发布-订阅模型都清楚,整个模型肯定要包括3种角色,发布者,订阅者(也叫监听者),事件。这三个角色有什么作用呢?

  • 发布者:触发事件的角色,触发以后,所有监听,也叫订阅该事件的监听者都会收到通知,发布者不需要知道有多少个监听者存在。

  • 订阅者:监听某个事件的发生,一旦发生事件,执行相应处理逻辑。

  • 事件:代表事件的实体,这个事件实体通常会包含某些信息,发布者将信息包装到事件内,订阅者可以获取该信息,达到传递信息的作用

spring本身定义了一个发布事件的方法,可以看成是发布者。

订阅者在spring容器内叫做ApplicationListener,是一个泛型接口,用户可以自己定义某一事件的订阅者,注册到容器中。

spring内部定义了一个ApplicationEvent抽象类,所有spring管理的事件都实现了ApplicationEvent类,他的一个子类ApplicationContextEvent也是一个抽象类,spring又定义了几个ApplicationContextEvent的子类,用于代表spring容器生命周期的典型事件,包括ContextStartedEvent,ContextRefreshedEvent,ContextStoppedEvent,ContextClosedEvent,发布这些容器生命周期事件的方法嵌入在容器的整个生命周期中。spring的实现原来在后面的原理分析中详细讲解。

发布者,订阅者spring已经有自己的实现机制,这里我们自定义一个实现ApplicationEvent的事件类,用于测试。

public class MyEvent extends ApplicationEvent {
   
    public MyEvent(Object source) {
   
        super(source);
    }
}

spring的事件机制有两种使用方式,分别是ApplicationListener接口方式基于EventListener注解方式

2.1 实现ApplicationListener接口方式

ApplicationListener是一个泛型接口,我们实现该接口,定义一个监听器。

@Component
public class MyApplicationListener implements ApplicationListener<MyEvent> {
   
    @Override
    public void onApplicationEvent(MyEvent event) {
   
        System.out.println("MyEvent事件发生");
        System.out.println("收到信息:" + event.getSource());
    }
}

在TestSpring启动类的main方法中加入下面两行代码

MyEvent myEvent = new MyEvent(context);
context.publishEvent(myEvent);

启动TestSpring类的main方法,显示结果

MyEvent事件发生
收到信息:org.springframework.context.annotation.AnnotationConfigApplicationContext@2e0fa5d3, started on Thu Feb 04 09:47:23 CST 2021
2.2 EventListener注解方式

创建一个测试类AnnotationEventTest,类中定义一个方法,注意方法必须有形参,不然会报错,方法添加EventListener注解,这就相当于监听了MyEvent事件的处理方法。

@Component
public class AnnotationEventTest {
   

    @EventListener
    public void test(MyEvent event)
    {
   
        System.out.println("事件测试:"+event);
    }
}

启动TestSpring类的main方法,显示结果:

事件测试:com.li.study.event.MyEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@2e0fa5d3, started on Fri Feb 05 08:22:11 CST 2021]

这种基于EventListener注解的方式,省掉了定义监听器类,用起来更方便。

很多人会有疑问,spring为什么会做这种事件通知机制?我理解主要为了解耦,事件的发布者不需要知道有多少监听者在监听该事件的发生。有人说这种功能也可以通过依赖注入的方式实现,把监听逻辑的实现类注入到发布事件的对象中,直接通过方法调用即可。我只能说,呃。。。你说的对,太郭敬明了。

3.原理分析

其实这个实现原理大家仔细一想,也很简单,无非就是spring自动识别所有的事件监听器,不管是实现ApplicationListener还是添加EventListener注解的方法,将所有的监听器注入到容器,每个监听器绑定了一个事件类型,ApplicationListener通过泛型的参数类型绑定,EventListener注解通过方法形参绑定。当容器触发事件时,遍历所有监听器,找到类型匹配的事件监听器,执行监听方法。

下面就从源码角度来分析spring的实现方式,分为两个主要步骤:事件监听器的自动注册和发布事件

3.1 事件监听器的注册原理

前面也提到,spring的事件监听器有两种形式,实现ApplicationListener接口和标记EventListener注解的方法。

3.1.1 实现ApplicationListener接口的事件监听器发现

自动注册ApplicationListener接口的实现类,实现原理是BeanPostProcessor后置处理器,后置处理器的实现原理参考BeanPostProcessor后置处理器原理与应用

限于篇幅,这里不详细说明。在上面的案例调用AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);时,会启动该并刷新容器,会执行AbstractApplicationContext类的refresh() 方法,在refresh() 方法中会执行很多复杂的逻辑,这个方法时spring的合新方法。其中有一行代码prepareBeanFactory(beanFactory);我们查看一下,在代码中有一行 beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));就是向spring容器中注册了一个发现事件监听器的BeanPostProcessor。

//省略无关代码
protected void prepareBeanFactory(ConfigurableListableBeanFactory bean
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值