Spring监听器用法与原理详解(带ApplicationListener模型图)(1)

简介: Spring监听器用法与原理详解(带ApplicationListener模型图)

前言

相信大家都或多或少知道Spring中的监听器,有些人还能说出它采用了观察者模式,但其实它还用到了适配器模式,工厂模式等。当然,仍有不少人是完全不了解Spring的监听及其机制的,本次我们就来深入学习一下Spring监听器


一、Spring监听器是什么

Spring监听器是一种特殊的类,它们能帮助开发者监听 web 中特定的事件,比如 ServletContext, HttpSession, ServletRequest 的创建和销毁;变量的创建、销毁等等。


当Web容器启动后,Spring的监听器会启动监听,监听是否创建ServletContext的对象,如果发生了创建ServletContext对象这个事件 (当web容器启动后一定会生成一个ServletContext对象,所以监听事件一定会发生),ContextLoaderListener类会实例化并且执行初始化方法,将spring的配置文件中配置的bean注册到Spring容器中


二、观察者模式

1. 模型介绍

观察者模式(Observer Pattern)是一种行为设计模式,它用于在对象之间建立一对多的依赖关系。在该模式中,当一个对象的状态发生变化时,它会自动通知其依赖对象(称为观察者),使它们能够自动更新


观察者模式的工作原理如下:


  1. 主题对象维护一个观察者列表,并提供方法用于添加和删除观察者。
  2. 当主题的状态发生变化时,它会遍历观察者列表,并调用每个观察者的通知方法。
  3. 观察者接收到通知后,根据通知进行相应的更新操作。

a0fa7a79f71f4dc9a4b449383ba2f083.png


2. 观察者模式Demo

一个观察者模式demo包括以下部分:


观察者实体

主题实体

所以我们先写个观察者接口:

import java.util.ArrayList;
import java.util.List;
interface Observer {
    void update();
}

再构建两个观察者实现类

// 具体观察者A
class ConcreteObserverA implements Observer {
    @Override
    public void update() {
        System.out.println("ConcreteObserverA收到更新通知");
    }
}
// 具体观察者B
class ConcreteObserverB implements Observer {
    @Override
    public void update() {
        System.out.println("ConcreteObserverB收到更新通知");
    }
}

然后定义主题接口

interface Subject {
    void registerObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers();
}

构建一个具体主题


// 具体主题
class ConcreteSubject implements Subject {
    private List<Observer> observers = new ArrayList<>();
    @Override
    public void registerObserver(Observer observer) {
        observers.add(observer);
    }
    @Override
    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }
    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update();
        }
    }
    public void doSomething() {
        System.out.println("主题执行某些操作...");
        notifyObservers(); // 执行操作后通知观察者
    }
}

测试代码

public class ObserverPatternDemo {
    public static void main(String[] args) {
        // 创建主题和观察者
        ConcreteSubject subject = new ConcreteSubject();
        Observer observerA = new ConcreteObserverA();
        Observer observerB = new ConcreteObserverB();
        // 注册观察者
        subject.registerObserver(observerA);
        subject.registerObserver(observerB);
        // 执行主题的操作,触发通知
        subject.doSomething();
    }
}

最后可以看到结果


主题执行某些操作…

ConcreteObserverA收到更新通知

ConcreteObserverB收到更新通知


三、Spring监听器应用

1. 新建监听器

1.1 实现ApplicationListener接口

在详细介绍Spring监听器前,我们以一个简单的demo来说明:

import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;
@Component
public class MyContextRefreshedListener implements ApplicationListener<ContextRefreshedEvent> {
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        System.out.println("应用程序上下文已刷新");
        // 在这里可以执行一些初始化操作
    }
}
  1. 我们创建了一个名为MyContextRefreshedListener* 的监听器,它实现了ApplicationListener接口,这意味着这个监听器监听的事件类型是ContextRefreshedEvent,并重写了 onApplicationEvent 方法。该方法在应用程序上下文被刷新时触发。

  2. 使用 @Component 注解将该监听器声明为一个Spring管理的组件,这样Spring会自动将其纳入到应用程序上下文中,并在适当的时候触发监听


1.2 使用@EventListener注解

除了手动写个类外,我们也可以找个现成的类,该类不需要继承或实现任何其他类,然后在它的某个方法上加上 @EventListener 注解,如下:

@Component
public class MyListener {
  @EventListener(ContextRefreshedEvent.class)
  public void methodA(ContextRefreshedEvent event) {
    System.out.println("应用程序上下文已刷新");
        // 在这里可以执行一些初始化操作
  }
}
  1. 在一个现有的类的某个方法上,加上@EventListener(ContextRefreshedEvent.class),Spring会在加载这个类时,为其创建一个监听器,这个监听器监听的事件类型是ContextRefreshedEvent,当此事件发生时,将触发执行该方法methodA。

  2. 使用 @Component 注解将该类声明为一个Spring管理的组件,这样Spring会自动将其纳入到应用程序上下文中,并在适当的时候触发监听

  3. 我们可以在这个类中写上多个方法,每个方法通过注解监听着不同的事件类型,这样我们就仅需使用一个类,却构建了多个监听器


上述两种方法的效果是一样的。那么最后,我们就完成了Spring中一个内置监听器的简单示例:当启动一个基于Spring的应用程序时,当应用程序上下文被刷新时,ContextRefreshedEvent事件将被触发,然后MyContextRefreshedListener监听器的onApplicationEvent方法将被调用。

2. 内置的事件类型

我们在demo中使用了一个 ContextRefreshedEvent 的事件,这个事件是Spring内置的事件,除了该事件,Spring还内置了一些其他的事件类型,分别在以下情况下触发:


  1. ContextRefreshedEvent:
  2. 当应用程序上下文被刷新时触发。这个事件在ApplicationContext初始化或刷新时被发布,适用于执行初始化操作和启动后的后续处理。例如,初始化缓存、预加载数据等。

  3. ContextStartedEvent:
  4. 当应用程序上下文启动时触发。这个事件在调用ApplicationContext的start()方法时被发布,适用于在应用程序启动时执行特定的操作。例如,启动定时任务、启动异步消息处理等。

  5. ContextStoppedEvent:
  6. 当应用程序上下文停止时触发。这个事件在调用ApplicationContext的stop()方法时被发布,适用于在应用程序停止时执行清理操作。例如,停止定时任务、关闭数据库连接等。

  7. ContextClosedEvent:
  8. 当应用程序上下文关闭时触发。这个事件在调用ApplicationContext的close()方法时被发布,适用于在应用程序关闭前执行最后的清理工作。例如,释放资源、保存日志等。

  9. RequestHandledEvent:
  10. 在Web应用程序中,当一个HTTP请求处理完成后触发。这个事件在Spring的DispatcherServlet处理完请求后被发布,适用于记录请求日志、处理统计数据等。

  11. ApplicationEvent:
  12. 这是一个抽象的基类,可以用于定义自定义的应用程序事件。你可以创建自定义事件类,继承自ApplicationEvent,并定义适合你的应用场景的事件类型。

3. 自定义事件与监听器Demo

在学习完上面的内容后,我们现在可以手动写个Spring的事件,以及对应的监听器的demo了


3.1 构建两个自定义事件

建立继承自ApplicationEvent的自定义事件类

// 事件A
public class CustomEventA extends ApplicationEvent {
    private String message;
    public CustomEventA(Object source, String message) {
        super(source);
        this.message = message;
    }
    public String getMessage() {
        return message;
    }
    public void setMessage(String message) {
        this.message = message;
    }
}
// 事件B
public class CustomEventB extends ApplicationEvent {
    private String message;
    public CustomEventB(Object source, String message) {
        super(source);
        this.message = message;
    }
    public String getMessage() {
        return message;
    }
    public void setMessage(String message) {
        this.message = message;
    }
}

3.2 构建监听

我们选用@EventListener注解来实现监听

@Component
public class MyListener {
  @EventListener(CustomEventA.class)
  public void methodA(CustomEventA event) {
    System.out.println("========我监听到事件A了:" + event.getMessage());
        // 在这里可以执行一些其他操作
  }
  @EventListener(CustomEventB.class)
  public void methodB(CustomEventB event) {
    System.out.println("========我监听到事件B了:" + event.getMessage());
        // 在这里可以执行一些其他操作
  }
}

3.3 发布事件

@Component
public class CustomEventPublisher implements ApplicationContextAware, ApplicationListener<ContextRefreshedEvent> {
    private ApplicationContext applicationContext;
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
    // 利用容器刷新好的消息为触发,发布两条自定义的事件
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        CustomEventA eventA = new CustomEventA(applicationContext , "我是AAAA");
        CustomEventB eventB = new CustomEventB(applicationContext , "我是BBBB");
        applicationContext.publishEvent(eventA);
        applicationContext.publishEvent(eventB);
    }
}

48339798a688437f93f18a3b1abf29f8.png

目录
相关文章
|
21天前
|
缓存 Java 开发者
【Spring】原理:Bean的作用域与生命周期
本文将围绕 Spring Bean 的作用域与生命周期展开深度剖析,系统梳理作用域的类型与应用场景、生命周期的关键阶段与扩展点,并结合实际案例揭示其底层实现原理,为开发者提供从理论到实践的完整指导。
|
12天前
|
缓存 安全 Java
Spring Security通用权限管理模型解析
Spring Security作为Spring生态的核心安全框架,结合RBAC与ACL权限模型,基于IoC与AOP构建灵活、可扩展的企业级权限控制体系,涵盖认证、授权流程及数据库设计、性能优化等实现策略。
72 0
|
19天前
|
人工智能 Java 开发者
【Spring】原理解析:Spring Boot 自动配置
Spring Boot通过“约定优于配置”的设计理念,自动检测项目依赖并根据这些依赖自动装配相应的Bean,从而解放开发者从繁琐的配置工作中解脱出来,专注于业务逻辑实现。
|
1月前
|
Java 关系型数据库 数据库
深度剖析【Spring】事务:万字详解,彻底掌握传播机制与事务原理
在Java开发中,Spring框架通过事务管理机制,帮我们轻松实现了这种“承诺”。它不仅封装了底层复杂的事务控制逻辑(比如手动开启、提交、回滚事务),还提供了灵活的配置方式,让开发者能专注于业务逻辑,而不用纠结于事务细节。
|
2月前
|
缓存 安全 Java
Spring 框架核心原理与实践解析
本文详解 Spring 框架核心知识,包括 IOC(容器管理对象)与 DI(容器注入依赖),以及通过注解(如 @Service、@Autowired)声明 Bean 和注入依赖的方式。阐述了 Bean 的线程安全(默认单例可能有安全问题,需业务避免共享状态或设为 prototype)、作用域(@Scope 注解,常用 singleton、prototype 等)及完整生命周期(实例化、依赖注入、初始化、销毁等步骤)。 解析了循环依赖的解决机制(三级缓存)、AOP 的概念(公共逻辑抽为切面)、底层动态代理(JDK 与 Cglib 的区别)及项目应用(如日志记录)。介绍了事务的实现(基于 AOP
115 0
|
2月前
|
监控 架构师 NoSQL
spring 状态机 的使用 + 原理 + 源码学习 (图解+秒懂+史上最全)
spring 状态机 的使用 + 原理 + 源码学习 (图解+秒懂+史上最全)
|
4月前
|
前端开发 Java 数据库连接
Spring核心原理剖析与解说
每个部分都是将一种巨大并且复杂的技术理念传达为更易于使用的接口,而这就是Spring的价值所在,它能让你专注于开发你的应用,而不必从头开始设计每一部分。
170 32
|
2月前
|
人工智能 安全 Java
Spring Boot 过滤器 拦截器 监听器
本文介绍了Spring Boot中的过滤器、拦截器和监听器的实现与应用。通过Filter接口和FilterRegistrationBean类,开发者可实现对请求和响应的数据过滤;使用HandlerInterceptor接口,可在控制器方法执行前后进行处理;利用各种监听器接口(如ServletRequestListener、HttpSessionListener等),可监听Web应用中的事件并作出响应。文章还提供了多个代码示例,帮助读者理解如何创建和配置这些组件,适用于构建更高效、安全和可控的Spring Boot应用程序。
519 0
|
XML 搜索推荐 Java
Spring源码 --- 监听器的原理 (下)
Spring源码 --- 监听器的原理 (下)
193 0
Spring源码 --- 监听器的原理 (下)
|
设计模式 Java Nacos
Spring源码 --- 监听器的原理 (上)
Spring源码 --- 监听器的原理
434 0
Spring源码 --- 监听器的原理 (上)