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

相关推荐
半夏知半秋18 小时前
skynet.dispatch与skynet.register_protocol
笔记·后端·学习·安全架构
蒋星熠18 小时前
网络协议深度解析:从OSI七层模型到现代互联网通信的技术实战
网络·后端·python·网络协议·http·性能优化·tcp
爱读源码的大都督19 小时前
2000字源码分析,聊聊Spring的扫描机制底层到底是如何实现的?
java·后端·spring
JavaGuide19 小时前
小厂 Java 面试,难度怎么样?
java·后端
Chan1619 小时前
【 设计模式 | 行为型模式 观察者模式 】
java·spring boot·后端·spring·观察者模式·设计模式·idea
一个帅气昵称啊20 小时前
在.NET中实现RabbitMQ客户端的优雅生命周期管理及二次封装
分布式·后端·架构·c#·rabbitmq·.net
FuckPatience21 小时前
ASP.NET Core RazorPages/MVC/Blazor/Razor/WebApi概念记录说明
后端·asp.net