首页 > 编程语言 >Spring事件详解,Spring-Event源码详解,一文搞透Spring事件管理

Spring事件详解,Spring-Event源码详解,一文搞透Spring事件管理

时间:2023-04-03 20:44:18浏览次数:33  
标签:Spring springframework event 详解 事件 context org 源码


文章目录

  • 一、Java中事件/监听器编程模型
  • 1、Java中Observable/Observer事件监听
  • (1)代码实例
  • (2)Java9新的事件监听
  • 2、面向接口的事件/监听器设计模式
  • 3、面向注解的事件/监听器设计模式
  • 二、Spring事件
  • 1、Spring标准事件-ApplicationEvent
  • 2、基于接口的 Spring 事件监听器
  • 代码实例
  • 3、基于注解的 Spring 事件监听器
  • 代码实例
  • 4、注册Spring ApplicationListener
  • 方法一:ApplicationListener 作为 Spring Bean 注册
  • 方法二:通过 ConfigurableApplicationContext API 注册
  • 方法三:直接使用注解@EventListener
  • 三种方式的执行顺序
  • 5、Spring 事件发布器
  • (1)源码分析
  • (2)依赖注入获取ApplicationEventPublisher
  • (3)依赖查找 ApplicationEventMulticaster
  • (4)ApplicationEventPublisher 发布事件
  • (5)ApplicationEventPublisher与ApplicationEventMulticaster的关联
  • 6、Spring 层次性上下文事件传播
  • 代码实例
  • 源码分析
  • 事件重复处理
  • 7、Spring 内建事件
  • 源码分析
  • 8、Spring 4.2 Payload 事件
  • 代码实例及分析
  • 9、自定义 Spring 事件
  • 10、同步和异步 Spring 事件广播
  • (1)基于实现类 - org.springframework.context.event.SimpleApplicationEventMulticaster
  • (2)基于注解 - @org.springframework.context.event.EventListener
  • (3)小tips
  • 11、Spring 4.1 事件异常处理
  • 源码分析
  • 代码实例
  • 12、Spring 事件/监听器实现原理
  • 源码分析
  • 基于注解的监听器如何注册
  • 三、扩展-Spring Boot 、Spring Cloud事件
  • 1、Spring Boot 事件
  • 2、Spring Cloud 事件
  • 参考资料

一、Java中事件/监听器编程模型

1、Java中Observable/Observer事件监听

设计模式 - 观察者模式扩展
• 可观者对象(消息发送者) - java.util.Observable
• 观察者 - java.util.Observer

标准化接口
• 事件对象 - java.util.EventObject
• 事件监听器 - java.util.EventListener

Observable/Observer 是观察者模型在 JDK 中的实现,而 EventObject 和 EventListener 是事件驱动的接口,这里有涉及实现,实现可以利用 Observable/Observer 或者扩展来完成。

Observable/Observer 是jdk中观察者模式的实现标准,有具体实现。但是事件驱动只是建议基于EventObject/EventListener来拓展,并没有具体实现。Spring事件并没有用到Observable/Observer ,并且Observable/Observer 在 jdk 9 被推荐转为java.util.concurrent.Flow实现。

JDK 中的 Observable/Observer 只是一个参考,它的执行顺序和插入顺序是相反,也即是它是 Stack 的方式,无法实现自定义顺序,并且它使用了 Vector 线程安全的集合容器,无法提升高性能,所以 Spring 没有必要用到它。

(1)代码实例

import java.util.EventListener;
import java.util.EventObject;
import java.util.Observable;
import java.util.Observer;

/**
 * Java 事件监听示例
 * {@link Observer} 示例
 */
public class ObserverDemo {

    public static void main(String[] args) {
        EventObservable observable = new EventObservable();
        // 添加观察者(监听者)
        observable.addObserver(new EventObserver());
        // 发布消息(事件)
        observable.notifyObservers("Hello,World");
    }

    static class EventObservable extends Observable {

        public void setChanged() {
            super.setChanged();
        }

        public void notifyObservers(Object arg) {
            setChanged(); // 需要手动打开开关
            super.notifyObservers(new EventObject(arg));
            clearChanged();
        }
    }

    static class EventObserver implements Observer, EventListener {

        @Override
        public void update(Observable o, Object event) {
            EventObject eventObject = (EventObject) event;
            System.out.println("收到事件 :" + eventObject);
        }
    }
}

(2)Java9新的事件监听

Observer和Observable在JDK9以后被废弃,因为观察者和可观察对象支持的事件模型是非常有限的,可观察对象传递的通知的顺序无法指定,状态变化与通知不能一一对应。

为了在线程之间可靠而有序地传递消息,可以考虑在java.util.concurrent包中使用一种并发数据结构。对于响应式流风格的编程,javaDOC提示考虑使用java.util.concurrent.Flow

2、面向接口的事件/监听器设计模式

事件/监听器场景举例:

Java 技术规范

事件接口

监听器接口

JavaBeans

java.beans.PropertyChangeEvent

java.beans.PropertyChangeListener

Java AWT

java.awt.event.MouseEvent

java.awt.event.MouseListener

Java Swing

javax.swing.event.MenuEvent

javax.swing.event.MenuListener

Java Preference

java.util.prefs.PreferenceChangeEvent

java.util.prefs.PreferenceChangeListener

通过上面列举的类的源码我们可以看到,Event都是继承了EventObject;Listener都是继承了EventListener,这基本是一个约定俗成的事情,Spring也不例外。

3、面向注解的事件/监听器设计模式

事件/监听器注解场景举例:

Java 技术规范

事件注解

监听器注解

Servlet 3.0+

@javax.servlet.annotation.WebListener

JPA 1.0+

@javax.persistence.PostPersist

Java Common

@PostConstruct

EJB 3.0+

@javax.ejb.PrePassivate

JSF 2.0+

@javax.faces.event.ListenerFor

二、Spring事件

1、Spring标准事件-ApplicationEvent

上面我们提到过,Java 标准事件 java.util.EventObject 扩展的扩展特性就是事件发生事件戳。

而Spring 应用上下文 ApplicationEvent 扩展就是 ApplicationContextEvent,Spring 应用上下文(ApplicationContext)作为事件源。
具体实现:
• org.springframework.context.event.ContextClosedEvent
• org.springframework.context.event.ContextRefreshedEvent
• org.springframework.context.event.ContextStartedEvent
• org.springframework.context.event.ContextStoppedEvent

分析源码我们可以看出,ApplicationEvent抽象类继承了jdk的EventObject,ApplicationContextEvent抽象类又继承了ApplicationEvent。

ApplicationContextEvent就是Spring应用上下文的一个事件源,提供了获取ApplicationContext方法,事件的source就是ApplicationContext。

ApplicationContextEvent有以上四个实现:ContextClosedEvent、ContextRefreshedEvent、ContextStartedEvent、ContextStoppedEvent。

2、基于接口的 Spring 事件监听器

Java 标准事件监听器 java.util.EventListener 扩展
• 扩展接口 - org.springframework.context.ApplicationListener
• 设计特点:单一类型事件处理
• 处理方法:onApplicationEvent(ApplicationEvent)
• 事件类型:org.springframework.context.ApplicationEvent

代码实例

import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.support.GenericApplicationContext;

GenericApplicationContext context = new GenericApplicationContext();

// 向 Spring 应用上下文注册事件
context.addApplicationListener(new ApplicationListener<ApplicationEvent>() {
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        System.out.println(("ApplicationListener - 接收到 Spring 事件:" + event));
    }
});

// 启动 Spring 应用上下文
context.refresh(); // ContextRefreshedEvent
// 启动 Spring 上下文(通常,ConfigurableApplicationContext#start() 方法是为了发布 ContextStartedEvent 事件,而真正的启动方法是 refresh() 方法。)
context.start();  // ContextStartedEvent
// 停止 Spring 上下文
context.stop();  // ContextStoppedEvent
// 关闭 Spring 应用上下文
context.close(); // ContextClosedEvent

我们通过该实例可以看出,Spring的四个事件通过Spring应用上下文的几个方法来触发的。

3、基于注解的 Spring 事件监听器

Spring 注解 - @org.springframework.context.event.EventListener

特性

说明

设计特点

支持多 ApplicationEvent 类型,无需接口约束

注解目标

方法

是否支持异步执行

支持

是否支持泛型类型事件

支持

是指支持顺序控制

支持,配合 @Order 注解控制

代码实例

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.event.*;
import org.springframework.core.annotation.Order;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;

@EnableAsync // 激活异步
public class MyApplicationListenerDemo {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();

        // 将引导类 MyApplicationListenerDemo 作为 Configuration Class
        context.register(MyApplicationListenerDemo.class);

        // 启动 Spring 应用上下文
        context.refresh(); // ContextRefreshedEvent
        // 启动 Spring 上下文
        context.start();  // ContextStartedEvent
        // 停止 Spring 上下文
        context.stop();  // ContextStoppedEvent
        // 关闭 Spring 应用上下文
        context.close(); // ContextClosedEvent
    }

    @EventListener
    @Async // 需要@EnableAsync
    public void onApplicationEventAsync(ContextRefreshedEvent event) {
        println("@EventListener(异步) - 接收到 Spring ContextRefreshedEvent");
    }

    @EventListener
    @Order(2)
    public void onApplicationEvent(ContextStartedEvent event) {
        println("@EventListener - 接收到 Spring ContextStartedEvent1");
    }
    @EventListener
    @Order(1) // 可以使用@Order控制顺序,数字越小越先执行
    public void onApplicationEvent2(ContextStartedEvent event) {
        println("@EventListener - 接收到 Spring ContextStartedEvent2");
    }

    @EventListener
    public void onApplicationEvent(ContextClosedEvent event) {
        println("@EventListener - 接收到 Spring ContextClosedEvent");
    }

    @EventListener
    public void onApplicationEvent(ContextStoppedEvent event) {
        println("@EventListener - 接收到 Spring ContextStoppedEvent");
    }

    private static void println(Object printable) {
        System.out.printf("[线程:%s] : %s\n", Thread.currentThread().getName(), printable);
    }
}

执行结果:

[线程:SimpleAsyncTaskExecutor-1] : @EventListener(异步) - 接收到 Spring ContextRefreshedEvent
[线程:main] : @EventListener - 接收到 Spring ContextStartedEvent2
[线程:main] : @EventListener - 接收到 Spring ContextStartedEvent1
[线程:main] : @EventListener - 接收到 Spring ContextStoppedEvent
[线程:main] : @EventListener - 接收到 Spring ContextClosedEvent

使用注解监听Spring事件相对而言比较简单,而且可以手动实现异步、进行排序。

4、注册Spring ApplicationListener

方法一:ApplicationListener 作为 Spring Bean 注册

// 基于 ApplicationListener 注册为 Spring Bean
// 通过 Configuration Class 来注册
context.register(MyApplicationListener.class);

public class MyApplicationListener implements ApplicationListener<ContextRefreshedEvent> {

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        println("MyApplicationListener - 接收到 Spring 事件:" + event);
    }
}

方法二:通过 ConfigurableApplicationContext API 注册

以上通过接口、注解的方式其实就是使用方法二的方式进行注册的

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();

// 将引导类 ApplicationListenerDemo 作为 Configuration Class
context.register(ApplicationListenerDemo.class);

// 基于 Spring 接口:向 Spring 应用上下文注册事件
// 基于 ConfigurableApplicationContext API 实现
context.addApplicationListener(new ApplicationListener<ApplicationEvent>() {
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        println("ApplicationListener - 接收到 Spring 事件:" + event);
    }
});

方法三:直接使用注解@EventListener

上面介绍过了

三种方式的执行顺序

通过运行代码我们发现,基于注解的Listener先执行,而后是基于接口的,最后才是注册为Bean的。

后面我们会通过分析源码来分析这个执行顺序的原因。

5、Spring 事件发布器

方法一:通过 ApplicationEventPublisher 发布 Spring 事件(事件发布)
• 获取 ApplicationEventPublisher:依赖注入

方法二:通过 ApplicationEventMulticaster 发布 Spring 事件(事件广播)
• 获取 ApplicationEventMulticaster:依赖注入、依赖查找

(1)源码分析

ApplicationEventPublisher接口有两个方法,其中有个方法是Spring4.2引入的。

@FunctionalInterface
public interface ApplicationEventPublisher {

	default void publishEvent(ApplicationEvent event) {
		publishEvent((Object) event);
	}

	void publishEvent(Object event);
}

ApplicationEventMulticaster接口会在ApplicationEventPublisher接口的基础上增加很多东西,包括对ApplicationListener的增删改查,multicastEvent方法就是事件广播方法。

public interface ApplicationEventMulticaster {

	void addApplicationListener(ApplicationListener<?> listener);

	void addApplicationListenerBean(String listenerBeanName);

	void removeApplicationListener(ApplicationListener<?> listener);
	
	void removeApplicationListenerBean(String listenerBeanName);

	void removeAllListeners();

	void multicastEvent(ApplicationEvent event);

	void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType);
}

(2)依赖注入获取ApplicationEventPublisher

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import javax.annotation.PostConstruct;

/**
 * 注入 {@link ApplicationEventPublisher} 示例
 */
public class InjectingApplicationEventPublisherDemo implements ApplicationEventPublisherAware,
        ApplicationContextAware, BeanPostProcessor {

    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;

    @Autowired
    private ApplicationContext applicationContext;

    @PostConstruct
    public void init() {
        //# 3
        applicationEventPublisher.publishEvent(new MySpringEvent("The event from @Autowired ApplicationEventPublisher"));
        // #4
        applicationContext.publishEvent(new MySpringEvent("The event from @Autowired ApplicationContext"));
    }

    public static void main(String[] args) {

        // 创建注解驱动 Spring 应用上下文
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();

        // 注册 Configuration Class
        context.register(InjectingApplicationEventPublisherDemo.class);

        // 增加 Spring 事件监听器
        context.addApplicationListener(new MySpringEventListener());

        // 启动 Spring 应用上下文
        context.refresh();

        // 关闭 Spring 应用上下文
        context.close();
    }

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { // #1
        applicationEventPublisher.publishEvent(new MySpringEvent("The event from ApplicationEventPublisherAware"));
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { // #2
        // ApplicationContext
        applicationEventPublisher.publishEvent(new MySpringEvent("The event from ApplicationContextAware"));
    }
}

通过以上实例我们可以看出,获取ApplicationEventPublisher 有两种方式,一种是通过 ApplicationEventPublisherAware 回调接口;一种是通过 @Autowired ApplicationEventPublisher。

而ApplicationContext也是继承了ApplicationEventPublisher,所以我们认为它也是一种ApplicationEventPublisher,也具有事件发布的能力。

(3)依赖查找 ApplicationEventMulticaster

查找条件
• Bean 名称:“applicationEventMulticaster”
• Bean 类型:org.springframework.context.event.ApplicationEventMulticaster

我们进行一下源码分析:

事实上,我们调用context.addApplicationListener()方法时,会委派给applicationEventMulticaster调用它的addApplicationListener方法。

// org.springframework.context.support.AbstractApplicationContext#addApplicationListener
@Override
public void addApplicationListener(ApplicationListener<?> listener) {
	Assert.notNull(listener, "ApplicationListener must not be null");
	if (this.applicationEventMulticaster != null) {
		this.applicationEventMulticaster.addApplicationListener(listener);
	}
	this.applicationListeners.add(listener);
}

而此处的applicationEventMulticaster初始化方法:

// org.springframework.context.support.AbstractApplicationContext#initApplicationEventMulticaster
protected void initApplicationEventMulticaster() {
	ConfigurableListableBeanFactory beanFactory = getBeanFactory();
	if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) { // applicationEventMulticaster
		this.applicationEventMulticaster =
				beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
		if (logger.isTraceEnabled()) {
			logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
		}
	}
	else {
		this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory); // 默认使用这个
		beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
		if (logger.isTraceEnabled()) {
			logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
					"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
		}
	}
}

initApplicationEventMulticaster这个方法是在springIOC容器refresh时被调用的。

而实际上ApplicationEventPublisher 发布事件的底层实现,也是通过getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType); 实现的。ApplicationEventPublisher 没有直接实现。

(4)ApplicationEventPublisher 发布事件

通过以下实例我们可以看出,实现了ApplicationEventPublisherAware 接口可以获取到ApplicationEventPublisher ,从而直接发送事件(这种事件貌似只能通过addApplicationListener添加的监听器接收到,通过注解的方式是接收不到的,具体原因尚不明确)。

import org.springframework.context.*;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MyApplicationListenerDemo implements ApplicationEventPublisherAware {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();

        // 将引导类 MyApplicationListenerDemo 作为 Configuration Class
        context.register(MyApplicationListenerDemo.class);
        context.addApplicationListener(new ApplicationListener<ApplicationEvent>() {
            @Override
            public void onApplicationEvent(ApplicationEvent event) {
                System.out.println(("ApplicationListener - 接收到 Spring 事件:" + event));
            }
        });

        // 启动 Spring 应用上下文
        context.refresh(); // ContextRefreshedEvent
        // 启动 Spring 上下文
        context.start();  // ContextStartedEvent
        // 停止 Spring 上下文
        context.stop();  // ContextStoppedEvent
        // 关闭 Spring 应用上下文
        context.close(); // ContextClosedEvent
    }


    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        applicationEventPublisher.publishEvent(new ApplicationEvent("Hello,World"){});

        // 发送 PayloadApplicationEvent
        applicationEventPublisher.publishEvent("Hello,World2");
    }

}

也可以通过通过 @Autowired ApplicationEventPublisher 来依赖注入ApplicationEventPublisher 。

(5)ApplicationEventPublisher与ApplicationEventMulticaster的关联

底层实现:
• 接口:org.springframework.context.event.ApplicationEventMulticaster
• 抽象类:org.springframework.context.event.AbstractApplicationEventMulticaster
• 实现类:org.springframework.context.event.SimpleApplicationEventMulticaster

实际上,ApplicationEventPublisher与ApplicationEventMulticaster之间是没有接口依赖关系的。

那么他们两个是怎么关联的呢?

我们通过context调用publishEvent方法,里面的逻辑我们再看一下:

protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
	Assert.notNull(event, "Event must not be null");

	// Decorate event as an ApplicationEvent if necessary
	ApplicationEvent applicationEvent;
	if (event instanceof ApplicationEvent) {
		applicationEvent = (ApplicationEvent) event;
	}
	else {
		applicationEvent = new PayloadApplicationEvent<>(this, event);
		if (eventType == null) {
			eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
		}
	}

	// Multicast right now if possible - or lazily once the multicaster is initialized
	if (this.earlyApplicationEvents != null) {
		this.earlyApplicationEvents.add(applicationEvent);
	}
	else {
		// 关键逻辑!获取ApplicationEventMulticaster
		getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
	}

	// Publish event via parent context as well...
	if (this.parent != null) {
		if (this.parent instanceof AbstractApplicationContext) {
			((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
		}
		else {
			this.parent.publishEvent(event);
		}
	}
}

我们可以看到,ApplicationEventPublisher的publishEvent方法底层其实是调用了ApplicationEventMulticaster的multicastEvent方法,而SimpleApplicationEventMulticaster作为ApplicationEventMulticaster的一个默认实现,是支持异步事件发送的:

// org.springframework.context.event.SimpleApplicationEventMulticaster#multicastEvent(org.springframework.context.ApplicationEvent, org.springframework.core.ResolvableType)
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
	ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
	Executor executor = getTaskExecutor();
	for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
		if (executor != null) {
			executor.execute(() -> invokeListener(listener, event));
		}
		else {
			invokeListener(listener, event);
		}
	}
}

话又说回来,earlyApplicationEvents 是什么呢?
其实这是Spring4开始支持的,就是早期的Event。Spring3其实有个bug,如果一个类同时实现ApplicationEventPublisherAware、BeanPostProcessor或者BeanFactoryPostProcessor,就会出问题。

SpringIOC在初始化时执行的refresh方法:

// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);

// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);

// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);

// Initialize message source for this context.
initMessageSource();

// Initialize event multicaster for this context.
initApplicationEventMulticaster();

// Initialize other special beans in specific context subclasses.
onRefresh();

// Check for listener beans and register them.
registerListeners();

// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);

// Last step: publish corresponding event.
finishRefresh();

我们发现,如果一个bean实现了BeanPostProcessor,会在initApplicationEventMulticaster初始化ApplicationEventMulticaster之前初始化,所以当此时发布事件的时候,ApplicationEventMulticaster还未初始化,导致报错,所以使用一个earlyApplicationEvents 临时存储,当registerListeners()方法执行完之后,此时ApplicationEventMulticaster已经完全初始化了,这时候取出所有存储的earlyApplicationEvents ,进行挨个事件发布。

所以,这相当于一个Spring的BUG,只不过在后期修复了。

6、Spring 层次性上下文事件传播

发生说明:
当 Spring 应用出现多层次 Spring 应用上下文(ApplicationContext)时,如 Spring WebMVC、Spring Boot或 Spring Cloud 场景下,由子 ApplicationContext 发起 Spring 事件可能会传递到其 Parent ApplicationContext(直到 Root)的过程。

如何避免:
定位 Spring 事件源(ApplicationContext)进行过滤处理。

代码实例

import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.event.ApplicationContextEvent;

import java.util.LinkedHashSet;
import java.util.Set;

/**
 * 层次性 Spring 事件传播实例
 */
public class HierarchicalSpringEventPropagateDemo {

    public static void main(String[] args) {
        // 1. 创建 parent Spring 应用上下文
        AnnotationConfigApplicationContext parentContext = new AnnotationConfigApplicationContext();
        parentContext.setId("parent-context");
        // 注册 MyListener 到 parent Spring 应用上下文
        parentContext.register(MyListener.class);

        // 2. 创建 current Spring 应用上下文
        AnnotationConfigApplicationContext currentContext = new AnnotationConfigApplicationContext();
        currentContext.setId("current-context");
        // 3. current -> parent
        currentContext.setParent(parentContext);
        // 注册 MyListener 到 current Spring 应用上下文
        currentContext.register(MyListener.class);

        // 4.启动 parent Spring 应用上下文
        parentContext.refresh();

        // 5.启动 current Spring 应用上下文
        currentContext.refresh();

        // 关闭所有 Spring 应用上下文
        currentContext.close();
        parentContext.close();
    }

    static class MyListener implements ApplicationListener<ApplicationContextEvent> {

        private
        //static
        Set<ApplicationContextEvent> processedEvents = new LinkedHashSet<>();

        @Override
        public void onApplicationEvent(ApplicationContextEvent event) {
            if (processedEvents.add(event)) {
                System.out.printf("监听到 Spring 应用上下文[ ID : %s ] 事件 :%s\n", event.getApplicationContext().getId(),
                        event.getClass().getSimpleName());
            }
        }
    }
}

执行结果:

监听到 Spring 应用上下文[ ID : parent-context ] 事件 :ContextRefreshedEvent
监听到 Spring 应用上下文[ ID : current-context ] 事件 :ContextRefreshedEvent
监听到 Spring 应用上下文[ ID : current-context ] 事件 :ContextRefreshedEvent
监听到 Spring 应用上下文[ ID : current-context ] 事件 :ContextClosedEvent
监听到 Spring 应用上下文[ ID : current-context ] 事件 :ContextClosedEvent
监听到 Spring 应用上下文[ ID : parent-context ] 事件 :ContextClosedEvent

我们可以看出,每个事件会执行三次,因为current执行完毕之后,还会在其parent中执行一次。

源码分析

我们可以看一下context的refresh方法触发的finishRefresh方法中publishEvent触发的事件逻辑:

// org.springframework.context.support.AbstractApplicationContext#publishEvent(java.lang.Object, org.springframework.core.ResolvableType)
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
	Assert.notNull(event, "Event must not be null");

	// Decorate event as an ApplicationEvent if necessary
	ApplicationEvent applicationEvent;
	if (event instanceof ApplicationEvent) {
		applicationEvent = (ApplicationEvent) event;
	}
	else {
		applicationEvent = new PayloadApplicationEvent<>(this, event);
		if (eventType == null) {
			eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
		}
	}

	// Multicast right now if possible - or lazily once the multicaster is initialized
	if (this.earlyApplicationEvents != null) {
		this.earlyApplicationEvents.add(applicationEvent);
	}
	else {
		getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
	}

	// Publish event via parent context as well...
	if (this.parent != null) { // 递归,如果有parent的话,就传递给parent进行事件发布
		if (this.parent instanceof AbstractApplicationContext) {
			((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
		}
		else {
			this.parent.publishEvent(event);
		}
	}
}

事件重复处理

比较简单的方式就是定义一个全局变量,如上我们的代码实例,定义了一个static的set做去重处理,同一个事件保证只能监听一次。

也可以注入ApplicationContext,判断事件的上下文对象是否是当前的上下文对象。从而进行过滤。

7、Spring 内建事件

ApplicationContextEvent 派生事件
• ContextRefreshedEvent :Spring 应用上下文就绪事件
• ContextStartedEvent :Spring 应用上下文启动事件
• ContextStoppedEvent :Spring 应用上下文停止事件
• ContextClosedEvent :Spring 应用上下文关闭事件

start 和 stop 方法是一种辅助的特性,通常使用不多。

源码分析

我们来分析一下context的refresh方法:

refresh方法最终会调用finishRefresh方法,会调用publishEvent方法发送ContextRefreshedEvent事件:

// org.springframework.context.support.AbstractApplicationContext#finishRefresh
protected void finishRefresh() {
	// Clear context-level resource caches (such as ASM metadata from scanning).
	clearResourceCaches();

	// Initialize lifecycle processor for this context.
	initLifecycleProcessor();

	// Propagate refresh to lifecycle processor first.
	getLifecycleProcessor().onRefresh();

	// Publish the final event.
	publishEvent(new ContextRefreshedEvent(this));

	// Participate in LiveBeansView MBean, if active.
	LiveBeansView.registerApplicationContext(this);
}

实际上,AbstractApplicationContext实现了ApplicationContext,ApplicationContext继承了ApplicationEventPublisher,所以在底层是可以发布事件的。

其他几个事件发送同理。

8、Spring 4.2 Payload 事件

Spring Payload 事件 - org.springframework.context.PayloadApplicationEvent

使用场景:简化 Spring 事件发送,关注事件源主体

发送方法:ApplicationEventPublisher#publishEvent(java.lang.Object)

代码实例及分析

import org.springframework.context.*;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MyApplicationListenerDemo implements ApplicationEventPublisherAware {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();

        // 将引导类 MyApplicationListenerDemo 作为 Configuration Class
        context.register(MyApplicationListenerDemo.class);
        context.addApplicationListener(new ApplicationListener<ApplicationEvent>() {
            @Override
            public void onApplicationEvent(ApplicationEvent event) {
                System.out.println(("ApplicationListener - 接收到 Spring 事件:" + event));
            }
        });

        // 启动 Spring 应用上下文
        context.refresh(); // ContextRefreshedEvent
        // 启动 Spring 上下文
        context.start();  // ContextStartedEvent
        // 停止 Spring 上下文
        context.stop();  // ContextStoppedEvent
        // 关闭 Spring 应用上下文
        context.close(); // ContextClosedEvent
    }


    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        applicationEventPublisher.publishEvent(new ApplicationEvent("Hello,World"){});

        // 发送 PayloadApplicationEvent
        applicationEventPublisher.publishEvent("Hello,World2");
        applicationEventPublisher.publishEvent(new HelloPayloadApplicationEvent(this, "Hello,World3"));
    }

    static class HelloPayloadApplicationEvent extends PayloadApplicationEvent<String> {

        public HelloPayloadApplicationEvent(Object source, String payload) {
            super(source, payload);
        }
    }
}

通过运行我们可以看出,使用下面这种方式发送PayloadApplicationEvent会报错:

applicationEventPublisher.publishEvent(new HelloPayloadApplicationEvent(this, "Hello,World3"));

错误提示:

Mismatched number of generics specified

当我们把HelloPayloadApplicationEvent类改一下:

static class HelloPayloadApplicationEvent<String> extends PayloadApplicationEvent<String> {

    public HelloPayloadApplicationEvent(Object source, String payload) {
        super(source, payload);
    }
}

此时就不会报错了,正常发送我们的事件。

实际上,Spring一直没有处理过这个问题,在Payload事件中Bean的泛型具体化并没有处理好。

关于Spring泛型处理:Spring泛型处理源码详解,Java泛型处理

所以,想要发送PayloadApplicationEvent事件,只需要使用上面的那种方式即可,不需要再继承、new一个Event了:

// 发送 PayloadApplicationEvent
applicationEventPublisher.publishEvent("Hello,World2");// (√)
applicationEventPublisher.publishEvent(new HelloPayloadApplicationEvent(this, "Hello,World3")); // (×)

9、自定义 Spring 事件

(1)扩展 org.springframework.context.ApplicationEvent

import org.springframework.context.ApplicationEvent;

/**
 * 自定义 Spring 事件
 */
public class MySpringEvent extends ApplicationEvent {

    /**
     * Create a new {@code ApplicationEvent}.
     *
     * @param message 事件消息
     */
    public MySpringEvent(String message) {
        super(message);
    }

    @Override
    public String getSource() {
        return (String) super.getSource();
    }

    public String getMessage() {
        return getSource();
    }
}

(2)实现 org.springframework.context.ApplicationListener

import org.springframework.context.ApplicationListener;

/**
 * 自定义 Spring 事件监听器
 */
public class MySpringEventListener implements ApplicationListener<MySpringEvent> {

    @Override
    public void onApplicationEvent(MySpringEvent event) {
        System.out.printf("[线程 : %s] 监听到事件 : %s\n", Thread.currentThread().getName(), event);
    }
}

(3)注册 org.springframework.context.ApplicationListener

GenericApplicationContext context = new GenericApplicationContext();

// 1.添加自定义 Spring 事件监听器
context.addApplicationListener(new MySpringEventListener());

// 2.启动 Spring 应用上下文
context.refresh();

// 3. 发布自定义 Spring 事件
context.publishEvent(new MySpringEvent("Hello,World"));

// 4. 关闭 Spring 应用上下文
context.close();

10、同步和异步 Spring 事件广播

(1)基于实现类 - org.springframework.context.event.SimpleApplicationEventMulticaster

模式切换:setTaskExecutor(java.util.concurrent.Executor) 方法
• 默认模式:同步
• 异步模式:如 java.util.concurrent.ThreadPoolExecutor

设计缺陷:非基于接口契约编程

源码分析:
ApplicationEventMulticaster的一个默认实现就是SimpleApplicationEventMulticaster,它的multicastEvent如下:

// org.springframework.context.event.SimpleApplicationEventMulticaster#multicastEvent(org.springframework.context.ApplicationEvent, org.springframework.core.ResolvableType)
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
	ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
	Executor executor = getTaskExecutor();
	for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
		if (executor != null) {
			executor.execute(() -> invokeListener(listener, event));
		}
		else {
			invokeListener(listener, event);
		}
	}
}

如果手动设置(setTaskExecutor)了taskExecutor,就是异步执行。

代码实例:

import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ApplicationEventMulticaster;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.SimpleApplicationEventMulticaster;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.scheduling.concurrent.CustomizableThreadFactory;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 异步事件处理器示例
 */
public class AsyncEventHandlerDemo {

    public static void main(String[] args) {

        GenericApplicationContext context = new GenericApplicationContext();

        // 1.添加自定义 Spring 事件监听器
        context.addApplicationListener(new MySpringEventListener());

        // 2.启动 Spring 应用上下文
        context.refresh(); // 初始化 ApplicationEventMulticaster

        // 依赖查找 ApplicationEventMulticaster
        ApplicationEventMulticaster applicationEventMulticaster =
                context.getBean(AbstractApplicationContext.APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);

        // 判断当前 ApplicationEventMulticaster 是否为 SimpleApplicationEventMulticaster
        if (applicationEventMulticaster instanceof SimpleApplicationEventMulticaster) {
            SimpleApplicationEventMulticaster simpleApplicationEventMulticaster =
                    (SimpleApplicationEventMulticaster) applicationEventMulticaster;
            // 切换 taskExecutor
            ExecutorService taskExecutor = Executors.newSingleThreadExecutor(new CustomizableThreadFactory("my-spring-event-thread-pool"));
            // 同步 -> 异步
            simpleApplicationEventMulticaster.setTaskExecutor(taskExecutor);

            // 添加 ContextClosedEvent 事件处理,优雅关闭线程池
            applicationEventMulticaster.addApplicationListener(new ApplicationListener<ContextClosedEvent>() {
                @Override
                public void onApplicationEvent(ContextClosedEvent event) {
                    if (!taskExecutor.isShutdown()) {
                        taskExecutor.shutdown();
                    }
                }
            });

        }

        // 3. 发布自定义 Spring 事件
        context.publishEvent(new MySpringEvent("Hello,World"));

        // 4. 关闭 Spring 应用上下文(ContextClosedEvent)
        context.close();

    }
}

import org.springframework.context.ApplicationListener;

/**
 * 自定义 Spring 事件监听器
 */
public class MySpringEventListener implements ApplicationListener<MySpringEvent> {

    @Override
    public void onApplicationEvent(MySpringEvent event) {
        System.out.printf("[线程 : %s] 监听到事件 : %s\n", Thread.currentThread().getName(), event);
    }
}

(2)基于注解 - @org.springframework.context.event.EventListener

模式切换
• 默认模式:同步
• 异步模式:标注 @org.springframework.scheduling.annotation.Async

实现限制:无法直接实现同步/异步动态切换

事实上注解方式实现异步,上面我们已经介绍过了。

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.CustomizableThreadFactory;

import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;

import static java.util.concurrent.Executors.newSingleThreadExecutor;

/**
 * 注解驱动异步事件处理器示例
 */
@EnableAsync // 激活 Spring 异步特性
public class AnnotatedAsyncEventHandlerDemo {

    public static void main(String[] args) {

        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();

        // 1. 注册当前类作为 Configuration Class
        context.register(AnnotatedAsyncEventHandlerDemo.class);

        // 2.启动 Spring 应用上下文
        context.refresh(); // 初始化 ApplicationEventMulticaster

        // 3. 发布自定义 Spring 事件
        context.publishEvent(new MySpringEvent("Hello,World"));

        // 4. 关闭 Spring 应用上下文(ContextClosedEvent)
        context.close();

    }

    @Async // 同步 -> 异步
    @EventListener
    public void onEvent(MySpringEvent event) {
        System.out.printf("[线程 : %s] onEvent方法监听到事件 : %s\n", Thread.currentThread().getName(), event);
    }

    @Bean
    public Executor taskExecutor() {
        ExecutorService taskExecutor = newSingleThreadExecutor(new CustomizableThreadFactory("my-spring-event-thread-pool-a"));
        return taskExecutor;
    }
}

(3)小tips

上面的例子我们可以看出,基于实现类SimpleApplicationEventMulticaster手动设置线程池的方式来实现异步,其实是全局设置。

而使用注解的方式,可以指定方法异步。

11、Spring 4.1 事件异常处理

Spring 3.0 错误处理接口 - org.springframework.util.ErrorHandler

使用场景:
• Spring 事件(Events):SimpleApplicationEventMulticaster Spring 4.1 开始支持
• Spring 本地调度(Scheduling):org.springframework.scheduling.concurrent.ConcurrentTaskScheduler和org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler

源码分析

上面我们分析到,SimpleApplicationEventMulticaster发布事件执行multicastEvent方法,最终会调用invokeListener来调用监听器:

// org.springframework.context.event.SimpleApplicationEventMulticaster#invokeListener
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
	ErrorHandler errorHandler = getErrorHandler();
	if (errorHandler != null) { // 如果有ErrorHandler 
		try {
			doInvokeListener(listener, event);
		}
		catch (Throwable err) {
			errorHandler.handleError(err);
		}
	}
	else { // 没有ErrorHandler 就直接执行
		doInvokeListener(listener, event);
	}
}

代码实例

public class AsyncEventHandlerDemo {

    public static void main(String[] args) {

        GenericApplicationContext context = new GenericApplicationContext();

        // 启动 Spring 应用上下文
        context.refresh(); // 初始化 ApplicationEventMulticaster

        // 依赖查找 ApplicationEventMulticaster
        ApplicationEventMulticaster applicationEventMulticaster =
                context.getBean(AbstractApplicationContext.APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);

        // 判断当前 ApplicationEventMulticaster 是否为 SimpleApplicationEventMulticaster
        if (applicationEventMulticaster instanceof SimpleApplicationEventMulticaster) {
            SimpleApplicationEventMulticaster simpleApplicationEventMulticaster =
                    (SimpleApplicationEventMulticaster) applicationEventMulticaster;

            simpleApplicationEventMulticaster.setErrorHandler(e -> {
                System.err.println("当 Spring 事件异常时,原因:" + e.getMessage());
            });
        }

        context.addApplicationListener(new ApplicationListener<MySpringEvent>() {
            @Override
            public void onApplicationEvent(MySpringEvent event) {
                System.out.printf("[线程 : %s] 监听到事件 : %s\n", Thread.currentThread().getName(), event);
                throw new RuntimeException("故意抛出异常");
            }
        });

        // 3. 发布自定义 Spring 事件
        context.publishEvent(new MySpringEvent("Hello,World"));

        // 4. 关闭 Spring 应用上下文(ContextClosedEvent)
        context.close();

    }
}

12、Spring 事件/监听器实现原理

通过上面我们的分析与实践,大致基本也了解了Spring 事件/监听器实现原理,在此我们进一步做一下总结。

核心类 - org.springframework.context.event.SimpleApplicationEventMulticaster

设计模式:观察者模式扩展
• 观察者 - org.springframework.context.ApplicationListener:API 添加、依赖查找
• 通知对象 - org.springframework.context.ApplicationEvent

执行模式:同步/异步

异常处理:org.springframework.util.ErrorHandler

泛型处理:org.springframework.core.ResolvableType

源码分析

SimpleApplicationEventMulticaster先继承了AbstractApplicationEventMulticaster,
AbstractApplicationEventMulticaster又实现了ApplicationEventMulticaster, BeanClassLoaderAware, BeanFactoryAware。

在addApplicationListener时,实际上发生了以下事情:

// org.springframework.context.event.AbstractApplicationEventMulticaster#addApplicationListener
@Override
public void addApplicationListener(ApplicationListener<?> listener) {
	synchronized (this.retrievalMutex) {
		// Explicitly remove target for a proxy, if registered already,
		// in order to avoid double invocations of the same listener.
		Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);
		if (singletonTarget instanceof ApplicationListener) {
			this.defaultRetriever.applicationListeners.remove(singletonTarget);
		}
		this.defaultRetriever.applicationListeners.add(listener);
		this.retrieverCache.clear();
	}
}

defaultRetriever就是ListenerRetriever一个内部类,保存着ApplicationListener的集合:

public final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<>();

在AbstractApplicationEventMulticaster定义了一个

final Map<ListenerCacheKey, ListenerRetriever> retrieverCache = new ConcurrentHashMap<>(64);

ListenerCacheKey就是将ApplicationEvent的泛型,里面存着ResolvableType。

实际上,我们上面分析到,调用multicastEvent方法时,会获取所有的ApplicationListener:

// org.springframework.context.event.SimpleApplicationEventMulticaster#multicastEvent(org.springframework.context.ApplicationEvent, org.springframework.core.ResolvableType)
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
	ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
	Executor executor = getTaskExecutor();
	for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
		if (executor != null) {
			executor.execute(() -> invokeListener(listener, event));
		}
		else {
			invokeListener(listener, event);
		}
	}
}
// org.springframework.context.event.AbstractApplicationEventMulticaster#getApplicationListeners(org.springframework.context.ApplicationEvent, org.springframework.core.ResolvableType)
protected Collection<ApplicationListener<?>> getApplicationListeners(
		ApplicationEvent event, ResolvableType eventType) {

	Object source = event.getSource();
	Class<?> sourceType = (source != null ? source.getClass() : null);
	ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);

	// Quick check for existing entry on ConcurrentHashMap...
	ListenerRetriever retriever = this.retrieverCache.get(cacheKey);
	if (retriever != null) {
		return retriever.getApplicationListeners(); // 一个类型关联多个监听器
	}

	if (this.beanClassLoader == null ||
			(ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&
					(sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
		// Fully synchronized building and caching of a ListenerRetriever
		synchronized (this.retrievalMutex) {
			retriever = this.retrieverCache.get(cacheKey);
			if (retriever != null) {
				return retriever.getApplicationListeners();
			}
			retriever = new ListenerRetriever(true);
			Collection<ApplicationListener<?>> listeners =
					retrieveApplicationListeners(eventType, sourceType, retriever);
			this.retrieverCache.put(cacheKey, retriever);
			return listeners;
		}
	}
	else {
		// No ListenerRetriever caching -> no synchronization necessary
		return retrieveApplicationListeners(eventType, sourceType, null);
	}
}

在获取所有的Listener时,会首先通过泛型构造一个ListenerCacheKey,来确定查找监听指定类型的监听器,迭代这些监听器挨个进行通知。

这也是可以解释了,为什么可以单独监听指定事件的类型了:

context.addApplicationListener(new ApplicationListener<ApplicationEvent>() {
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        println("ApplicationListener - 接收到 Spring 事件:" + event);
    }
});

context.addApplicationListener(new ApplicationListener<ContextRefreshedEvent>() {
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        println("ApplicationListener - 接收到 Spring 事件:" + event);
    }
});

基于注解的监听器如何注册

1.org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors(org.springframework.beans.factory.support.BeanDefinitionRegistry) 注册所有相关注解的post processor到beanRegistry里面,其中就包括监 听器相关的EventListenerMethodProcessor

2.该类的这个方法org.springframework.context.event.EventListenerMethodProcessor#afterSingletonsInstantiated会在bean实例化的中被调用。

3.org.springframework.context.event.EventListenerMethodProcessor#processBean 最终在这个方法找到相关注解并不listener注册到ApplicationContext中

其实spring的很多功能都是通过扩展post processor来完成的。

三、扩展-Spring Boot 、Spring Cloud事件

1、Spring Boot 事件

事件类型

发生时机

ApplicationStartingEvent

当 Spring Boot 应用已启动时

ApplicationStartedEvent

当 Spring Boot 应用已启动时

ApplicationEnvironmentPreparedEvent

当 Spring Boot Environment 实例已准备时

ApplicationPreparedEvent

当 Spring Boot 应用预备时

ApplicationReadyEvent

当 Spring Boot 应用完全可用时

ApplicationFailedEvent

当 Spring Boot 应用启动失败时

实际上,Spring Boot事件基本上还是使用Spring事件那一套-ApplicationEvent。

也是用的ApplicationEventPublisher来发布的事件。

关于SpringBoot事件详细用法请移步:
Springboot启动之后立即执行某些方法可以怎么做?Springboot监听器,Springboot生命周期钩子函数总结大全

2、Spring Cloud 事件

事件类型

发生时机

EnvironmentChangeEvent

当 Environment 示例配置属性发生变化时

HeartbeatEvent

当 DiscoveryClient 客户端发送心跳时

InstancePreRegisteredEvent

当服务实例注册前

InstanceRegisteredEvent

当服务实例注册后

RefreshEvent

当 RefreshEndpoint 被调用时

RefreshScopeRefreshedEvent

当 Refresh Scope Bean 刷新后

Spring Cloud 事件和Spring事件也都差不多,Spring Cloud 事件会分到不同的功能模块里面。

参考资料

极客时间-《小马哥讲 Spring 核心编程思想》


标签:Spring,springframework,event,详解,事件,context,org,源码
From: https://blog.51cto.com/u_13540373/6167344

相关文章

  • Spring注解驱动原理及源码,深入理解Spring注解驱动
    文章目录一、Java注解入门大全二、Spring注解驱动编程发展历程1、注解驱动启蒙时代:SpringFramework1.x@Transactional@ManagedResource2、注解驱动过渡时代:SpringFramework2.x@Repository@Component3、注解驱动黄金时代:SpringFramework3.x4、注解驱动完善时代:SpringFramewo......
  • Spring 类型转换详解,SpringBean创建时属性类型转换源码详解
    文章目录一、概述1、Spring类型转换的实现2、使用场景3、源码分析二、基于JavaBeans接口的类型转换1、代码实例2、Spring內建PropertyEditor扩展ByteArrayPropertyEditor3、自定义PropertyEditor扩展整合到springframework代码实例SpringPropertyEditor的设计缺陷三、Spr......
  • Go mod包依赖管理工具使用详解
    我个人觉得,一个包管理工具应该有以下功能:基本功能依赖管理依赖包版本控制对应的包管理平台可以私有化部署加分:代码包是否可以复用构建,测试,打包发布上线对比上面几点:目前做的最好的也就maven了,gradle没有使用过,不知道。今天主角是gomod,先来谈谈没有使用gomod之前的问题。使......
  • MA35D1记录1-源码编译
    今天年假结束,突然发现新唐即将发布MA35D1,去官网和git仓库查了下,新唐趁我放假又偷偷更新了一些资料。之前发布的是yocto的环境,那个我倒也用,但时不时要翻墙,对国内用户来说,多少有点恶心人,今天再去看,终于单独发出linux部分的源码。趁着工作任务不是很重,简单试一下1.源码下载在官网仓......
  • SpringBoot启动异常的错误①
    java:无法访问org.springframework.boot.SpringApplication错误的类文件:/D:/maven/repository/org/springframework/boot/spring-boot/3.0.5/spring-boot-3.0.5.jar!/org/springframework/boot/SpringApplication.class类文件具有错误的版本61.0,应为52.0 2023-04......
  • S5PV210开发 -- UART 详解
    上一篇文章系统的讲了一下通信的分类,包括并行通信,串行通信。串行通信的分类,包括同步通信,异步通信。这篇文章我们主要讲一下UART 串口编程,我们并不陌生。之前讲过RS485通信,参看:UNIX再学习--RS485串口编程再者,参看:日常生活小技巧--UART回环测试一、基本概念 参看:UART--维......
  • LIVE555再学习 -- testOnDemandRTSPServer 源码分析
    一、简介先看一下官网上的介绍:testOnDemandRTSPServer createsaRTSPserverthatcanstream,viaRTPunicast,fromvarioustypesofmediafile,ondemand.(Supportedmediatypesinclude:MPEG-1or2audioorvideo(elementarystream),includingMP3audio;MPEG-4......
  • LIVE555再学习 -- testH264VideoStreamer 源码分析
    上一篇文章我们已经讲了一部分:testH264VideoStreamer重复从H.264基本流视频文件(名为“test.264”)中读取,并使用RTP多播进行流式传输。 该程序还具有内置的RTSP服务器。Apple的“QuickTime播放器”可用于接收和播放此音频流。要使用它,让玩家打开会话的“rtsp://”URL(程序在......
  • LIVE555再学习 -- testRTSPClient 源码分析
    现在开讲 testRTSPClient。在官网这这样一段介绍,参看:RTSPclient翻译下来就是:testRTSPClient是一个命令行程序,显示如何打开和接收由RTSPURL指定的媒体流,即以rtsp://开头的URL在这个演示应用中,接收到的音频/视频数据什么也没有。但是,您可以在自己的应用程序中使用和调整此代码(......
  • IDEA Spring-boot 使用@Component注解的工具类,用@Autowired注入 @Service或者@Reposit
    IDEASpring-boot使用@Component注解的工具类,用@Autowired注入@Service或者@Repository会空指针(使用@PostContruct)原文链接:https://blog.csdn.net/ld_secret/article/details/104627597/使用idea编译器时,对于spring-boot的项目,大都使用注解,那么:一、现象:@Component标注的U......