栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Listener工作机制

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Listener工作机制

1.监听器

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

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

	
	  触发一个application context的事件
	void onApplicationEvent(E event);

}

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

	private class ContextRefreshListener implements ApplicationListener {

		@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 {

	
	public ApplicationContextEvent(ApplicationContext source) {
		super(source);
	}

	
	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 {

    //@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 {
    
    public MyEvent(Object source) {
        super(source);
    }
}

2.修改自定义的监听器,监听这个事件

3.触发事件


这里context可以调用publishEvent,是因为applicationcontext继承了一个事件发布接口,该类中有方法可以发布事件。方法实现在AbstractApplicationContext类中



也是调用这个方法 获取广播器 实现广播

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

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/865123.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号