Spring的容器内部事件发布

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
简介:

《Spring揭秘》阅读笔记

自定义事件机制

  • 给出自定义事件类型
    在某些应用场景下,我们希望关注特定功能的执行情况,这种功能的开始或者结束或者异常都可以看做一个事件,因此需要定义自己的事件类型。
package com.javadu.event;

import java.util.EventObject;

public class MethodExecutionEvent extends EventObject {
    private String methodName;

    public MethodExecutionEvent(Object source) {
        super(source);
    }

    public MethodExecutionEvent(Object source, String methodName) {
        super(source);
        this.methodName = methodName;
    }

    public String getMethodName() {
        return methodName;
    }

    public void setMethodName(String methodName) {
        this.methodName = methodName;
    }
}
  • 实现针对自定义事件类的事件监听器接口
    监听器负责处理具体的事件,当某个事件发生时,监听器也给出具体的回应。在这个例子中,监听器会在目标方法执行开始或者执行结束时响应对应的事件并处理。
package com.javadu.event;

import java.util.EventListener;

public interface MethodExecutionEventListener extends EventListener {
    void onMethodBegin(MethodExecutionEvent evt);
    void onMethodEnd(MethodExecutionEvent evt);
}

EventListener接口的作用仅仅在于“标记”,具体要提供哪些功能需要开发者自己定义,而且,还需要为自己定义的接口提供一个默认的实现类——只有接口的话什么也做不了。

package com.javadu.event;

public class SimpleMethodExecutionEventListener implements MethodExecutionEventListener {
    public void onMethodBegin(MethodExecutionEvent evt) {
        String methodName = evt.getMethodName();
        System.out.println("start to execute the method[" + methodName + "]");
    }

    public void onMethodEnd(MethodExecutionEvent evt) {
        String methodName = evt.getMethodName();
        System.out.println("finished to execute the method[" + methodName + "]");
    }
}
  • 组合事件类和监听器,发布事件
    这个是一个测试用例,首先需要准备测试环境:事件类+监听器;然后再发布事件,就可以看到监听器对事件的处理。

    public class MethodExecutionEventPublisher {
      private List<MethodExecutionEventListener> listeners = new ArrayList<MethodExecutionEventListener>();
    
      public void addMethodExecutionEventListener(MethodExecutionEventListener listener) {
          this.listeners.add(listener);
      }
    
      public void methodToMonitor() {
          MethodExecutionEvent event2Publish = new MethodExecutionEvent(this, "methodToMonitor");
          //发布方法开始执行的事件
          publishEvent(MethodExecutionStatus.BEGIN, event2Publish);
    
          //执行实际的方法逻辑
          //……
          //发布方法执行结束的事件
          publishEvent(MethodExecutionStatus.END, event2Publish);
      }
    
      protected void publishEvent(MethodExecutionStatus status, MethodExecutionEvent methodExecutionEvent) {
          List<MethodExecutionEventListener> copyListeners = new ArrayList<MethodExecutionEventListener>(listeners);
          for (MethodExecutionEventListener listener: copyListeners) { //发布事件,同时调用对应的监听器方法
              if (MethodExecutionStatus.BEGIN.equals(status)) {
                  listener.onMethodBegin(methodExecutionEvent);
              } else {
                  listener.onMethodEnd(methodExecutionEvent);
              }
          }
      }
    
      public void removeListener(MethodExecutionEventListener listener) {
          if (this.listeners.contains(listener)) {
              this.listeners.remove(listener);
          }
      }
    
      public void removeAllListeners() {
          this.listeners.clear();
      }
    
      public static void main(String[] args) {
          MethodExecutionEventPublisher eventPublisher = new MethodExecutionEventPublisher();
          eventPublisher.addMethodExecutionEventListener(new SimpleMethodExecutionEventListener()); //组合事件类和监听器
          eventPublisher.methodToMonitor();//发布事件
      }
    }

    Java SE中标准的自定义事件实现就是这个样子,涉及三个角色,即自定义事件类型、自定义的事件监听器和自定义的事件发布者,如下图所示:


JavaSE中自定义的事件结构图

Spring 的容器内事件发布类结构

Spring的ApplicationContext容器内部允许以 org.springframework.context.ApplicationEvent的形式发布事件, 容器内注册的org.springframework.context.ApplicationListener类型的bean定义会被ApplicationContext容器自动识别,它们负责监容器内发布的所有ApplicationEvent类型的事件。也就是说,一旦容器内发布ApplicationEvent及其子类型的事件,注册到容器的ApplicationListener就会对这些事件进行处理。

  • ApplicationEvent:Spring容器内的事件类型,继承自java.util.EventObject,这是一个抽象类,Spring提供了三个具体的实现——ContextCloseEvent、ContextRefreshedEvent和RequestHandleEvent。
  • ApplicationListener: Spring容器内使用的事件监听接口,继承自java.util.EventListener。ApplicationContext容器启动时,会自动识别并加载EventListener类型的bean定义,一旦容器中有ApplicationEvent事件发布,就会通知这些监听器。
  • ApplicationContext: ApplicationContext容器的具体实现类在实现事件的发布和事件监 器的注册方面,并没事必躬亲,而是把这些活儿转包给了一个称作org.springframework.context.event.ApplicationEventMulticaster的接口。该接口定义了具体事件监器的注册管理以及事件发布的方法,但接口终归是接口,还得有具体实现。ApplicationEventMulticaster有一抽象实现类:org.spring-framework.context.event.AbstractApplicationEventMulticaster,它实现了事件监 器的管理功能。出于灵活性和扩展性考虑,事件的发布功能则委托给了其子类。org.springframework.context.event.SimpleApplicationEventMulticaster 是 Spring提供的AbstractApplicationEventMulticaster的一个子类实现,添加了事件发布功能的实现。

综上,Spring容器内部事件发布的类图描述如下:


Spring容器内部事件发布实现类图

应用场景

Spring的ApplicationContext容器内的事件发布机制,主要用于单一容器内的简单消息通知和处理,并不适合分布式、多进程、多容器之间的事件通知。虽然可以通过Spring的Remoting支持,“曲折一点”来实现较为复杂的需求,但是难免弊大于利,失大于得。其他消息机制处理较复杂场景或许更合适。所以,我们应该在合适的地点、合适的需求分析的前提下,合理地使用Spring提供的ApplicationContext容器内的事件发布机制。



相关文章
|
7天前
|
XML Java 数据格式
Spring容器Bean之XML配置方式
通过对以上内容的掌握,开发人员可以灵活地使用Spring的XML配置方式来管理应用程序的Bean,提高代码的模块化和可维护性。
37 6
|
4月前
|
XML Java 数据格式
Spring5入门到实战------7、IOC容器-Bean管理XML方式(外部属性文件)
这篇文章是Spring5框架的实战教程,主要介绍了如何在Spring的IOC容器中通过XML配置方式使用外部属性文件来管理Bean,特别是数据库连接池的配置。文章详细讲解了创建属性文件、引入属性文件到Spring配置、以及如何使用属性占位符来引用属性文件中的值。
Spring5入门到实战------7、IOC容器-Bean管理XML方式(外部属性文件)
|
23天前
|
安全 Java 开发者
Spring容器中的bean是线程安全的吗?
Spring容器中的bean默认为单例模式,多线程环境下若操作共享成员变量,易引发线程安全问题。Spring未对单例bean做线程安全处理,需开发者自行解决。通常,Spring bean(如Controller、Service、Dao)无状态变化,故多为线程安全。若涉及线程安全问题,可通过编码或设置bean作用域为prototype解决。
32 1
|
1月前
|
前端开发 Java Docker
使用Docker容器化部署Spring Boot应用程序
使用Docker容器化部署Spring Boot应用程序
|
1月前
|
Java Docker 微服务
利用Docker容器化部署Spring Boot应用
利用Docker容器化部署Spring Boot应用
51 0
|
2月前
|
Java 测试技术 Windows
咦!Spring容器里为什么没有我需要的Bean?
【10月更文挑战第11天】项目经理给小菜分配了一个紧急需求,小菜迅速搭建了一个SpringBoot项目并完成了开发。然而,启动测试时发现接口404,原因是控制器包不在默认扫描路径下。通过配置`@ComponentScan`的`basePackages`字段,解决了问题。总结:`@SpringBootApplication`默认只扫描当前包下的组件,需要扫描其他包时需配置`@ComponentScan`。
|
3月前
|
XML Java 开发者
经典面试---spring IOC容器的核心实现原理
作为一名拥有十年研发经验的工程师,对Spring框架尤其是其IOC(Inversion of Control,控制反转)容器的核心实现原理有着深入的理解。
156 3
|
2月前
|
XML Java 数据格式
Spring IOC容器的深度解析及实战应用
【10月更文挑战第14天】在软件工程中,随着系统规模的扩大,对象间的依赖关系变得越来越复杂,这导致了系统的高耦合度,增加了开发和维护的难度。为解决这一问题,Michael Mattson在1996年提出了IOC(Inversion of Control,控制反转)理论,旨在降低对象间的耦合度,提高系统的灵活性和可维护性。Spring框架正是基于这一理论,通过IOC容器实现了对象间的依赖注入和生命周期管理。
80 0
|
4月前
|
XML Java 数据格式
Spring5入门到实战------3、IOC容器-Bean管理XML方式(一)
这篇文章详细介绍了Spring框架中IOC容器的Bean管理,特别是基于XML配置方式的实现。文章涵盖了Bean的定义、属性注入、使用set方法和构造函数注入,以及如何注入不同类型的属性,包括null值、特殊字符和外部bean。此外,还探讨了内部bean的概念及其与外部bean的比较,并提供了相应的示例代码和测试结果。
Spring5入门到实战------3、IOC容器-Bean管理XML方式(一)
|
4月前
|
XML Java 数据格式
Spring5入门到实战------5、IOC容器-Bean管理(三)
这篇文章深入探讨了Spring5框架中IOC容器的高级Bean管理,包括FactoryBean的使用、Bean作用域的设置、Bean生命周期的详细解释以及Bean后置处理器的实现和应用。
Spring5入门到实战------5、IOC容器-Bean管理(三)