SpringBoot中的监听机制

SpringBoot中内置的监听器

内置监听器都定义在在spring.factories文件中

监听器 监听事件 说明
ClearCachesApplicationListener ContextRefreshedEvent 当触发ContextRefreshedEvent事件会清空应用的缓存
ParentContextCloserApplicationListener ParentContextAvailableEvent 触发ParentContextAvailableEvent事件会完成父容器关闭的监听器
CloudFoundryVcapEnvironmentPostProcessor ApplicationPreparedEvent 判断环境中是否存在VCAP_APPLICATION或者VCAP_SERVICES。如果有就添加Cloud Foundry的配置;没有就不执行任何操作。
FileEncodingApplicationListener ApplicationEnvironmentPreparedEvent 文件编码的监听器
AnsiOutputApplicationListener ApplicationEnvironmentPreparedEvent 根据 spring.output.ansi.enabled参数配置 AnsiOutput
ConfigFileApplicationListener ApplicationEnvironmentPreparedEventApplicationPreparedEvent 完成相关属性文件的加载,application.properties、 application.yml
DelegatingApplicationListener ApplicationEnvironmentPreparedEvent 监听到事件后转发给环境变量 context.listener.classes指定的那些事件监听器
ClasspathLoggingApplicationListener ApplicationEnvironmentPreparedEventApplicationFailedEvent 一个SmartApplicationListener,对环境就绪事件ApplicationEnvironmentPreparedEvent/应用失败事件ApplicationFailedEvent做出响应,往日志DEBUG级别输出TCCL(thread context class loader)的classpath。
LoggingApplicationListener ApplicationStartingEvent ApplicationEnvironmentPreparedEvent ApplicationPreparedEventContextClosedEventApplicationFailedEvent 配置 LoggingSystem。使用 logging.config环境变量指定的配置或者缺省配置
LiquibaseServiceLocatorApplicationListener ApplicationStartingEvent 使用一个可以和Spring Boot可执行jar包配合工作的版本替换liquibase ServiceLocator
BackgroundPreinitializer ApplicationStartingEventApplicationReadyEventApplicationFailedEvent 尽早触发一些耗时的初始化任务,使用一个后台线程

自定义监听器和监听事件

自定义监听事件

需要继承ApplicationEvent

scala 复制代码
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);
    }
}

自定义监听器

需要实现ApplicationListener接口

csharp 复制代码
/**
 * @author 26917
 * 自定义监听器
 *  监听自定义的事件
 */
public class MyCustomerEventListener implements ApplicationListener<MyEvent> {
    @Override
    public void onApplicationEvent(MyEvent event) {
        System.out.println("MyCustomerEventListener ----》 自定义事件触发" + event);
    }
}

ApplicationListener类图

将这个自定义的监听器加入到spring.factories文件中

ini 复制代码
org.springframework.context.ApplicationListener=\
com.nyc.listener.MyCustomerEventListener

使用这个监听器

typescript 复制代码
@RestController
public class UserController {
    @Autowired
    private ApplicationContext context;
    @GetMapping("/hello")
    public String hello(){
        context.publishEvent(new MyEvent(new Object()));
        return "hello";
    }
}

监听器代码分析

类图分析

getRunListeners(args)方法

这个方法获取到事件发布器

EventPublishingRunListener 构造方法

kotlin 复制代码
public EventPublishingRunListener(SpringApplication application, String[] args) {
    this.application = application;
    this.args = args;
    // 初始化多个监听器,其实就是我们前面加载的spring.factories文件中的11个监听器
    this.initialMulticaster = new SimpleApplicationEventMulticaster();
    // application.getListeners() 获取11个监听器
    for (ApplicationListener<?> listener : application.getListeners()) {
        // 绑定初始的11个监听器
        this.initialMulticaster.addApplicationListener(listener);
    }
}

listeners.starting()方法

触发启动事件 -》发布starting事件,那么监听starting事件的监听器就会触发

typescript 复制代码
class SpringApplicationRunListeners {

	private final Log log;

	private final List<SpringApplicationRunListener> listeners;

	SpringApplicationRunListeners(Log log, Collection<? extends SpringApplicationRunListener> listeners) {
		this.log = log;
		this.listeners = new ArrayList<>(listeners);
	}

	void starting() {
		// 发布器 EventPublishingRunListener
		for (SpringApplicationRunListener listener : this.listeners) {
			listener.starting();
		}
	}

	void environmentPrepared(ConfigurableEnvironment environment) {
		for (SpringApplicationRunListener listener : this.listeners) {
			listener.environmentPrepared(environment);
		}
	}

	void contextPrepared(ConfigurableApplicationContext context) {
		for (SpringApplicationRunListener listener : this.listeners) {
			listener.contextPrepared(context);
		}
	}

	void contextLoaded(ConfigurableApplicationContext context) {
		for (SpringApplicationRunListener listener : this.listeners) {
			listener.contextLoaded(context);
		}
	}

	void started(ConfigurableApplicationContext context) {
		for (SpringApplicationRunListener listener : this.listeners) {
			listener.started(context);
		}
	}

	void running(ConfigurableApplicationContext context) {
		for (SpringApplicationRunListener listener : this.listeners) {
			listener.running(context);
		}
	}

	void failed(ConfigurableApplicationContext context, Throwable exception) {
		for (SpringApplicationRunListener listener : this.listeners) {
			callFailedListener(listener, context, exception);
		}
	}

	private void callFailedListener(SpringApplicationRunListener listener, ConfigurableApplicationContext context,
			Throwable exception) {
		try {
			listener.failed(context, exception);
		}
		catch (Throwable ex) {
			if (exception == null) {
				ReflectionUtils.rethrowRuntimeException(ex);
			}
			if (this.log.isDebugEnabled()) {
				this.log.error("Error handling failed", ex);
			}
			else {
				String message = ex.getMessage();
				message = (message != null) ? message : "no error message";
				this.log.warn("Error handling failed (" + message + ")");
			}
		}
	}

}

SpringApplicationRunListeners类的作用

SpringApplicationRunListener 的集合代理类,用来统一调度并触发所有 RunListener,整体监视 Spring Boot 启动过程的各个阶段。

在源码中SpringApplicationRunListener接口的默认实现就只有,EventPublishingRunListener

EventPublishingRunListener类的starting方法。

typescript 复制代码
@Override
public void starting() {
    this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
}

在springboot的启动的时候会在以下几个阶段进行监听器发布,分别是启动阶段、环境配置准备阶段、容器上下文准备阶段、启动完成阶段、启动失败阶段以及运行阶段。

相关推荐
Olaf_n12 小时前
SpringBoot启动流程
后端
DS小龙哥12 小时前
基于STM32设计的智能盲人辅助导航系统设计
后端
DS小龙哥12 小时前
基于华为云设计的智能宠物喂养管理系统
后端
David爱编程12 小时前
synchronized 的可重入性:避免死锁的隐藏武器
java·后端
二闹13 小时前
Python字符串格式化:谁才是真正的硬汉?
后端·python
Livingbody13 小时前
零代码实践自然语言处理 - 文本分类任务实现,以qwen模型和OpenAI SDK为例
后端
FrankYoou13 小时前
spring boot autoconfigure 自动配置的类,和手工 @configuration + @bean 本质区别
java·spring boot·后端
lovebugs13 小时前
JVM内存迷宫:破解OutOfMemoryError的终极指南
java·后端·面试
Swift社区13 小时前
66项目中 Spring Boot 配置文件未生效该如何解决
java·spring boot·后端