Spring原理解析 之扩展原理-ApplicationListener

本文深入探讨了Spring框架中的事件监听机制,包括ApplicationListener接口的使用,事件的发布与监听,以及SpringBoot环境下事件的默认行为。介绍了如何自定义事件和监听器,展示了多种事件监听的实现方式。

简介

 * 3、ApplicationListener:监听容器中发布的事件。事件驱动模型开发;
 * 	  public interface ApplicationListener<E extends ApplicationEvent>
 * 		监听 ApplicationEvent 及其下面的子事件;
 * 
 * 	 步骤:
 * 		1)、写一个监听器(ApplicationListener实现类)来监听某个事件(ApplicationEvent及其子类)
 * 			@EventListener;
 * 			原理:使用EventListenerMethodProcessor处理器来解析方法上的@EventListener;
 * 
 * 		2)、把监听器加入到容器;
 * 		3)、只要容器中有相关事件的发布,我们就能监听到这个事件;
 * 				ContextRefreshedEvent:容器刷新完成(所有bean都完全创建)会发布这个事件;
 * 				ContextClosedEvent:关闭容器会发布这个事件;
 * 		4)、发布一个事件:
 * 				applicationContext.publishEvent();

案例

创建一个自定义事件监听器类。

import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

@Component
public class MyApplicationListener implements ApplicationListener<ApplicationEvent> {

    //当容器中发布此事件以后,方法触发
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        System.out.println("收到事件:"+event);
    }
}

测试类,并发布一个事件。

@Test
public void test(){
    AnnotationConfigApplicationContext applicationContext  = new AnnotationConfigApplicationContext(SpringConfig.class);
    //发布事件;
    applicationContext.publishEvent(new ApplicationEvent(new String("我发布的事件")) {
    });
    applicationContext.close();
}

输出结果

收到事件:org.springframework.context.event.ContextRefreshedEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@2db0f6b2: startup date [Sun Sep 15 16:28:36 CST 2019]; root of context hierarchy]
收到事件:com.demo.IOCTest$1[source=我发布的事件]
收到事件:org.springframework.context.event.ContextClosedEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@2db0f6b2: startup date [Sun Sep 15 16:28:36 CST 2019]; root of context hierarchy]

ApplicationListener简介

依赖于Spring框架,在Spring启动时调用。在普通Spring应用中一般监听ContextRefreshedEvent事件。

ApplicationContext事件机制是观察者设计模式的实现,通过ApplicationEvent类和ApplicationListener接口,可以实现ApplicationContext事件处理。
如果容器中有一个ApplicationListener Bean,每当ApplicationContext发布ApplicationEvent时,ApplicationListener Bean将自动被触发。这种事件机制都必须需要程序显示的触发。
其中spring有一些内置的事件,当完成某种操作时会发出某些事件动作。比如监听ContextRefreshedEvent事件,当所有的bean都初始化完成并被成功装载后会触发该事件,实现ApplicationListener<ContextRefreshedEvent>接口可以收到监听动作,然后可以写自己的逻辑。

同样事件可以自定义、监听也可以自定义,完全根据自己的业务逻辑来处理。

需要注意的是,在普通Spring环境中,基于ApplicationListener的监听器的onApplicationEvent方法可能会被执行多次,所以需要添加以下判断:

public void onApplicationEvent(ContextRefreshedEvent event) {
    //root application context 没有parent
    if(event.getApplicationContext().getParent() == null){
    
    }
}

Spring的事件

ApplicationEvent:事件本身 事件接口。
ApplicationListener:事件监听者 事件监听器接口,所有的监听器都实现该接口。
ApplicationEventPublisher:事件发布者 事件发布接口,ApplicationContext实现了该接口。
ApplicationEventMulticaster: Spring事件机制中的事件广播器,执行事件。

执行流程:
当一个事件源产生事件时,它通过事件发布器ApplicationEventPublisher发布事件,然后事件广播器ApplicationEventMulticaster会去事件注册表ApplicationContext中找到事件监听器ApplicationListnener,并且逐个执行监听器的onApplicationEvent方法,从而完成事件监听器的逻辑。

Spring默认启动事件

  • ContextRefreshedEvent:ApplicationContext 被初始化或刷新时,该事件被发布。这也可以在 ConfigurableApplicationContext接口中使用 refresh() 方法来发生。此处的初始化是指:所有的Bean被成功装载,后处理Bean被检测并激活,所有Singleton Bean 被预实例化,ApplicationContext容器已就绪可用。
  • ContextStartedEvent:当使用 ConfigurableApplicationContext (ApplicationContext子接口)接口中的 start() 方法启动 ApplicationContext 时,该事件被发布。你可以调查你的数据库,或者你可以在接受到这个事件后重启任何停止的应用程序。
  • ContextStoppedEvent:当使用 ConfigurableApplicationContext 接口中的 stop() 停止 ApplicationContext 时,发布这个事件。你可以在接受到这个事件后做必要的清理的工作。
  • ContextClosedEvent:当使用 ConfigurableApplicationContext 接口中的 close() 方法关闭 ApplicationContext 时,该事件被发布。一个已关闭的上下文到达生命周期末端;它不能被刷新或重启。
  • RequestHandledEvent:这是一个 web-specific 事件,告诉所有 bean HTTP 请求已经被服务。只能应用于使用DispatcherServlet的Web应用。在使用Spring作为前端的MVC控制器时,当Spring处理用户请求结束后,系统会自动触发该事件。

SpringBoot默认启动事件

  • ApplicationStartingEvent: SpringBoot启动开始的时候执行的事件
  • ApplicationEnvironmentPreparedEvent: SpringBoot对应Enviroment已经准备完毕,但此时上下文context还没有创建。在该监听中获取到ConfigurableEnvironment后可以对配置信息做操作,例如:修改默认的配置信息,增加额外的配置信息等等。
  • ApplicationPreparedEvent: SpringBoot上下文context创建完成,但此时Spring中的bean是没有完全加载完成的。在获取完上下文后,可以将上下文传递出去做一些额外的操作。值得注意的是:在该监听器中是无法获取自定义bean并进行操作的。
  • ApplicationReadyEvent: SpringBoot加载完成时候执行的事件。
  • ApplicationFailedEvent: SpringBoot启动异常时执行事件。

Spring环境下的实现事件发布监听的方法

自定义事件,继承自ApplicationEvent抽象类。

@Getter
@Setter
public class MyApplicationEvent extends ApplicationEvent {

    private String msg;

    public MyApplicationEvent(Object source, String msg) {
        super(source);
        this.msg = msg;
    }

}

自定义监听事件的发布:

@Resource
private ApplicationContext applicationContext;
applicationContext.publishEvent(new MyApplicationEvent("测试事件", msg));

SpringBoot进行事件监听有四种方式:
1、写代码向ApplicationContext中添加监听器\

// 实现ApplicationListener接口
public class MyApplicationListener implements ApplicationListener<MyApplicationEvent> {

    @Override
    public void onApplicationEvent(MyApplicationEvent myApplicationEvent) {
        System.out.println("监听到事件源:" + myApplicationEvent);
    }
}

// 装载监听
@SpringBootApplication
public class MqProviderApplication {

    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(MqProviderApplication.class);
        app.addListeners(new MyApplicationListener());//加入自定义的监听类
        app.run(args);
    }

}

2、使用Component注解将监听器装载入Spring容器

@Component
public class MyApplicationListener implements ApplicationListener<MyApplicationEvent> {

    @Override
    public void onApplicationEvent(MyApplicationEvent myApplicationEvent) {
        System.out.println("监听到事件源:" + myApplicationEvent);
    }
}

3、在application.yml中配置监听器

public class MyApplicationListener implements ApplicationListener<MyApplicationEvent> {
    @Override
    public void onApplicationEvent(MyApplicationEvent myApplicationEvent) {
        System.out.println("监听到事件源:" + myApplicationEvent);
    }
}
context:
  listener:
    classes: com.provider.listener.MyApplicationListener

4、通过@EventListener注解实现事件监听

import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

@Component
public class MyApplicationListener {

    @EventListener(classes = MyApplicationEvent.class)
    public void onApplicationEvent(MyApplicationEvent myApplicationEvent) {
        System.out.println("监听到事件源:" + myApplicationEvent);
    }
}

参考:
理解 Spring ApplicationListener
Spring监听器之ApplicationListener原理及源码解析及实例

Java8新特性及实战视频教程完整版Java 8 API添了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。 Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。使用Lambda 表达式可以使代码变的更简洁紧凑。Java8实战视频-01让方法参数具备行为能力Java8实战视频-02Lambda表达式初探Java8实战视频-03Lambda语法精讲Java8实战视频-04Lambda使用深入解Java8实战视频-05Lambda方法推导详细解-上.wmvJava8实战视频-06Lambda方法推导详细解-下Java8实战视频-07Stream入门及Stream在JVM中的线程表现Java8实战视频-08Stream知识点总结Stream源码阅读Java8实战视频-09如何创建Stream上集Java8实战视频-10如何创建Stream下集.wmvJava8实战视频-11Stream之filter,distinct,skip,limit,map,flatmap详细介绍Java8实战视频-12Stream之Find,Match,Reduce详细介绍Java8实战视频-13NumericStream的详细介绍以及和Stream之间的相互转换Java8实战视频-14Stream综合练习,熟练掌握API的用法Java8实战视频-15在Optional出现之前经常遇到的空指针异常.wmvJava8实战视频-16Optional的介绍以及API的详解Java8实战视频-17Optional之flatMap,综合练习,Optional源码剖Java8实战视频-18初识Collector体会Collector的强大Java8实战视频-19Collector使用方法深入详细介绍-01Java8实战视频-20Collector使用方法深入详细介绍-02Java8实战视频-21Collector使用方法深入详细介绍-03.wmvJava8实战视频-22Collector使用方法深入详细介绍-04Java8实战视频-23Collector原理讲解,JDK自带Collector源码深度剖Java8实战视频-24自定义Collector,结合Stream的使用详细介绍Java8实战视频-25Parallel Stream编程体验,充分利用多核机器快计算速度Java8实战视频-26Fork Join框架实例深入讲解Java8实战视频-27Spliterator接口源码剖以及自定义Spliterator实现一个Stream.wmvJava8实战视频-28Default方法的介绍和简单的例子Java8实战视频-29Default方法解决多重继承冲突的三大则详细介绍Java8实战视频-30多线程Future设计模式原理详细介绍,并且实现一个Future程序Java8实战视频-31JDK自带Future,Callable,ExecutorService介绍Java8实战视频-32实现一个异步基于事件回调的Future程序.wmvJava8实战视频-33CompletableFuture用法入门介绍Java8实战视频-34CompletableFuture之supplyAsync详细介绍Java8实战视频-35CompletableFuture流水线工作,join多个异步任务详细讲解Java8实战视频-36CompletableFuture常用API的重点详解-上Java8实战视频-37CompletableFuture常用API的重点详解-下Java8实战视频-38JDK老DateAPI存在的问题,新的DateAPI之LocalDate用法及其介绍.wmvJava8实战视频-39New Date API之LocalTime,LocalDateTime,Instant,Duration,Period详细介绍Java8实战视频-40New Date API之format和parse介绍
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值