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

相关推荐
鬼火儿12 小时前
SpringBoot】Spring Boot 项目的打包配置
java·后端
cr7xin12 小时前
缓存三大问题及解决方案
redis·后端·缓存
间彧13 小时前
Kubernetes的Pod与Docker Compose中的服务在概念上有何异同?
后端
间彧13 小时前
从开发到生产,如何将Docker Compose项目平滑迁移到Kubernetes?
后端
间彧13 小时前
如何结合CI/CD流水线自动选择正确的Docker Compose配置?
后端
间彧13 小时前
在多环境(开发、测试、生产)下,如何管理不同的Docker Compose配置?
后端
间彧13 小时前
如何为Docker Compose中的服务配置健康检查,确保服务真正可用?
后端
间彧13 小时前
Docker Compose和Kubernetes在编排服务时有哪些核心区别?
后端
间彧13 小时前
如何在实际项目中集成Arthas Tunnel Server实现Kubernetes集群的远程诊断?
后端
brzhang14 小时前
读懂 MiniMax Agent 的设计逻辑,然后我复刻了一个MiniMax Agent
前端·后端·架构