Listener工作机制

1.监听器

触发事件时通过监听器完成业务逻辑。
1.系统类监听器

// 可以注册自己感兴趣的事件的监听器,当有事件发生时,会自动根据注册的事件类型
// 来进行过滤和触发事件
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
    
    

	/**
	 * Handle an application event.
	 * @param event the event to respond to
	 */
	  触发一个application context的事件
	void onApplicationEvent(E event);

}

其实现类如ContextRefreshListener,注册的事件就是ContextRefreshEvent。

	private class ContextRefreshListener implements ApplicationListener<ContextRefreshedEvent> {
    
    

		@Override
		public void onApplicationEvent(ContextRefreshedEvent event) {
    
    
			FrameworkServlet.this.onApplicationEvent(event);
		}
	}

2.运行时监听器 SpringApplicationRunListener
SpringApplicationRunListener 接口规定了 SpringBoot 的生命周期,在各个生命周期广播相应的事件,调用实际的 ApplicationListener 类。通过对 SpringApplicationRunListener 的分析,也可以对 SpringBoot 的整个启动过程的理解会有很大帮助。


public interface SpringApplicationRunListener {
    
    
	//当run方法首次启动时立即调用。可用于非常早期的初始化。
	void starting();
	//在准备好环境后,但在创建ApplicationContext之前调用。
	void environmentPrepared(ConfigurableEnvironment environment);
	//在创建和准备好ApplicationContext之后,但在加载源之前调用。
	void contextPrepared(ConfigurableApplicationContext context);
	//在加载应用程序上下文后但刷新之前调用
	void contextLoaded(ConfigurableApplicationContext context);
	//上下文已刷新,应用程序已启动,但尚未调用commandlinerunner和applicationrunner。
	void started(ConfigurableApplicationContext context);
	//在运行方法完成之前立即调用,此时应用程序上下文已刷新,
	//并且所有commandlinerunner和applicationrunner都已调用。
	//2.0 才有
	void running(ConfigurableApplicationContext context);
	//在运行应用程序时发生故障时调用。2.0 才有
	void failed(ConfigurableApplicationContext context, Throwable exception);
}

3.SpringApplicationRunListeners
SpringApplicationRunListeners 是SpringApplicationRunListener的集合,里面包括了很多SpringApplicationRunListener实例;SpringApplication 类实际上使用的是 SpringApplicationRunListeners 类,与 SpringApplicationRunListener 生命周期相同,调用各个周期的 SpringApplicationRunListener 。然后广播相应的事件到 ApplicationListener。
在这里插入图片描述

2.事件events

相当于是容器启动的各个时间点
1.抽象类 ApplicationEvent

// 该抽象类需要被具体的事件实现才又意义,这也是设置为abstract的原因
public abstract class ApplicationEvent extends EventObject {
    
    

	// 事件发生的时间点
	private final long timestamp;

	// 构造函数
	public ApplicationEvent(Object source) {
    
    
		// 设置事件源码
		super(source);
		this.timestamp = System.currentTimeMillis();
	}

	// 返回事件发生的时间
	public final long getTimestamp() {
    
    
		return this.timestamp;
	}

}

spring中事件主要分为两类,一类是和应用程序上下文相关的事件,一类是和应用程序上下文处理请求相关的事件。
1.应用程序上下文相关的事件
抽象类

public abstract class ApplicationContextEvent extends ApplicationEvent {
    
    

	/**
	 * Create a new ContextStartedEvent.
	 * @param source the {@code ApplicationContext} that the event is raised for
	 * (must not be {@code null})
	 */
	public ApplicationContextEvent(ApplicationContext source) {
    
    
		super(source);
	}

	/**
	 * Get the {@code ApplicationContext} that the event was raised for.
	 */
	public final ApplicationContext getApplicationContext() {
    
    
		return (ApplicationContext) getSource();
	}

}

具体实现
在这里插入图片描述
2.
在这里插入图片描述
EventObject 事件对象
ApplicationEvent 应用事件
SpringApplicationEvent Spring中的系统事件
ApplicationPreparedEvent 该事件表示:应用已经准备好
ApplicationReadyEvent 该事件表示:应用已经就绪
ApplicationStartedEvent 该事件表示:容器已经启动
ApplicationFailedEvent 该事件表示:容器启动失败
ApplicationEnvironmentPreparedEvent 该事件表示:应用上下文环境已经准备完成
ApplicationContextInitializedEvent 该事件表示:应用启动完成
在这里插入图片描述
starting: 环境一启动就发出
environmentPrepared: 环境已准备妥当,即 已将系统和自定义的的一些属性已加载到容器内
contextInitialized:springboot已经启动,并且准备好了上下文,这个是在加载bean之前发布的
prepared:应用上下文已经创建完毕,但bean还没有完全加载完成
started: springboot已经将bean实例化完成了,但是还没调用CommandLineRunner和ApplicationRunner 这两个接口
ready:CommandLineRunner和ApplicationRunner 调用完毕后发出
failed:启动运行中如果发生错误会发送该事件

3.广播器ApplicationEventMulticaster

可以将当前事件广播给感兴趣的监听器,也就是查找感兴趣的监听器,然后完成监听器方法的执行

// 通过该接口,可以实现管理一组ApplicationListener对象,并且可以给他们发布事件,ApplicationEventPublisher
// 可以委派ApplicationEventMulticaster来真正的发布事件
public interface ApplicationEventMulticaster {
    
    

	// 添加一个监听所有事件的监听器
	void addApplicationListener(ApplicationListener<?> listener);

	// 添加一个监听所有事件的监听器的spring bean
	void addApplicationListenerBean(String listenerBeanName);

	// 从事件通知列表中删除一个监听器
	void removeApplicationListener(ApplicationListener<?> listener);

	// 从事件通知列表中删除一个监听器
	void removeApplicationListenerBean(String listenerBeanName);

	// 删除事件广播器中所有的事件监听器
	void removeAllListeners();

	// 广播给定的application事件到合适的监听器
	void multicastEvent(ApplicationEvent event);

	// 广播给定的application事件到合适的监听器
	void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType);
}

4.触发机制

定义在SpringApplicationRunListener 接口的这些方法
第一种触发机制
starting
在这里插入图片描述
调用EventPublishingRunListener的starting方法,这个类是SpringApplicationRunListener唯一的实现类。
在这里插入图片描述
然后调用SimpleApplicationEventMulticaster的multicastEvent方法。这个类是EventPublishingRunListener的一个成员变量
在这里插入图片描述

在这里插入图片描述

在这个方法中会获得对当前事件感兴趣的监听器 当前事件是ApplicationStartingEvent。
对这个事件感兴趣的监听器有4个
在这里插入图片描述

1.LoggingApplicationListener
发现这个类没有对任何事件感兴趣,但是它实现了一个接口
在这里插入图片描述
这个接口对 ApplicationEvent事件感兴趣
在这里插入图片描述

ApplicationEvent是SpringApplicationEvent的父类,SpringApplicationEvent是ApplicationStartingEvent的父类,所以该监听器相当于对当前事件ApplicationStartingEvent感兴趣,所以会被找到。
在这里插入图片描述
在这里插入图片描述

2.BackgroundPreinitializer
在这里插入图片描述
再来看一个不对这个事件感兴趣的监听器 比如FileEncodingApplicationListener
可以看出这个监听器对ApplicationEnvironmentPreparedEvent感兴趣。所以当这个事件发生时,这个监听器不会启动
在这里插入图片描述
找到监听之后,就会调用invokeListener(listener, event)方法
在这里插入图片描述
最终会调用每个listener的onApplicationEvent方法 这个doInvokeListener方法在SimpleApplicationEventMulticaster这个类中 这个类是EventPublishingRunListener的一个成员变量
在这里插入图片描述

例如LoggingApplicationListener类的onApplicationEvent方法

	public void onApplicationEvent(ApplicationEvent event) {
    
    
		if (event instanceof ApplicationStartingEvent) {
    
    
			onApplicationStartingEvent((ApplicationStartingEvent) event);
		}
		else if (event instanceof ApplicationEnvironmentPreparedEvent) {
    
    
			onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent) event);
		}
		else if (event instanceof ApplicationPreparedEvent) {
    
    
			onApplicationPreparedEvent((ApplicationPreparedEvent) event);
		}
		else if (event instanceof ContextClosedEvent
				&& ((ContextClosedEvent) event).getApplicationContext().getParent() == null) {
    
    
			onContextClosedEvent();
		}
		else if (event instanceof ApplicationFailedEvent) {
    
    
			onApplicationFailedEvent();
		}
	}

此时会进入第一个判断 ,执行相关操作。

总结下
主启动类构造函数中注册监听器,run方法中先注册run监听器,然后触发事件,通过广播器进行广播,找到对当前事件感兴趣的监听器。调用监听器方法完成业务逻辑。

5.自定义监听器监听系统事件

第一步:自定义一监听器

//实现监听器接口 指明感兴趣的事件
public class MyListener implements ApplicationListener<ApplicationStartingEvent> {
    
    

    //@Override
    //public void onApplicationEvent(MyEvent event) {
    
    
    //    System.out.println("1111");
    //    System.out.println(event);
    //}

	//重写方法 当事件触发时调用 
    @Override
    public void onApplicationEvent(ApplicationStartingEvent event) {
    
    
		//获取到主启动类
        System.out.println(event.getSpringApplication().getMainApplicationClass());
        System.out.println(event);
    }
}

第二步:创建spring.factories文件,指明自定义监听器的路径
在这里插入图片描述
第三步:主启动类启动,触发ApplicationStartingEvent
在这里插入图片描述

6.自定义事件

1创建自定义事件类 继承ApplicationEvent ,重写构造方法

public class MyEvent extends ApplicationEvent {
    
    
    /**
     * Create a new {@code ApplicationEvent}.
     *
     * @param source the object on which the event initially occurred or with
     *               which the event is associated (never {@code null})
     */
    public MyEvent(Object source) {
    
    
        super(source);
    }
}

2.修改自定义的监听器,监听这个事件
在这里插入图片描述
3.触发事件
在这里插入图片描述
在这里插入图片描述
这里context可以调用publishEvent,是因为applicationcontext继承了一个事件发布接口,该类中有方法可以发布事件。方法实现在AbstractApplicationContext类中

在这里插入图片描述
在这里插入图片描述
也是调用这个方法 获取广播器 实现广播
在这里插入图片描述

参考链接1
参考链接2
参考链接3

猜你喜欢

转载自blog.csdn.net/weixin_46666822/article/details/124628597