手动实现一个监听器(天气预报的模拟) 定义事件事件
监听器
广播器
触发机制
//事件接口
public interface WeatherEvent {
String getWeather();
}
//下雨事件
public class RainWeatherEvent implements WeatherEvent {
@Override
public String getWeather() {
return "rain";
}
}
//下雪事件
public class SnowWeatherEvent implements WeatherEvent {
@Override
public String getWeather() {
return "snow";
}
}
定义监听器
//监听器接口
public interface WeatherListener {
void doWeatherListener(WeatherEvent event);
}
//下雨监听器
public class RainWeatherListener implements WeatherListener {
@Override
public void doWeatherListener(WeatherEvent event) {
if (event instanceof RainWeatherEvent) {
System.out.println(this + " --- the weather is " + event.getWeather());
}
}
}
//下雪监听器
public class SnowWeatherListener implements WeatherListener {
@Override
public void doWeatherListener(WeatherEvent event) {
if (event instanceof SnowWeatherEvent) {
System.out.println( this + " --- the weather is " + event.getWeather());
}
}
}
定义广播器
//事件广播器接口
public interface EventBroadcast {
//事件广播
void broadcast(WeatherEvent event);
//注册监听器
void addListener(WeatherListener listener);
//溢出监听器
void removeListener(WeatherListener listener);
}
//模板方法 定义抽象的事件广播器
public abstract class AbstractEventBroadcast implements EventBroadcast {
//注册的所有的时间监听器
public List weatherListenerList;
@Override
public void broadcast(WeatherEvent event){
doStart(event);
if (null != weatherListenerList && weatherListenerList.size() > 0) {
weatherListenerList.stream().forEach(listener -> listener.doWeatherListener(event));
}
doEnd(event);
}
@Override
public void addListener(WeatherListener listener) {
if (null == weatherListenerList) {
weatherListenerList = Lists.newArrayList();
}
weatherListenerList.add(listener);
}
@Override
public void removeListener(WeatherListener listener) {
if (null != weatherListenerList) {
weatherListenerList.remove(listener);
}
}
//广播前动作
abstract void doStart(WeatherEvent event);
//广播后动作
abstract void doEnd(WeatherEvent event);
}
//实现抽象的广播器模板方法
public class WeatherEventBroadcast extends AbstractEventBroadcast {
@Override
void doStart(WeatherEvent event) {
System.out.println("开始向所有监听器广播天气事件--------------start");
}
@Override
void doEnd(WeatherEvent event) {
System.out.println("完成向所有监听器广播天气事件--------------end");
}
}
SpringBoot系统监听器介绍
监听器ApplicationListener的类介绍
@FunctionalInterface public interface ApplicationListener系统广播器ApplicationEventMulticaster的类介绍extends EventListener { void onApplicationEvent(E event); }
public interface ApplicationEventMulticaster {
void addApplicationListener(ApplicationListener> listener);
void addApplicationListenerBean(String listenerBeanName);
void removeApplicationListener(ApplicationListener> listener);
void removeApplicationListenerBean(String listenerBeanName);
void removeApplicationListeners(Predicate> predicate);
void removeApplicationListenerBeans(Predicate predicate);
void removeAllListeners();
void multicastEvent(ApplicationEvent event);
void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType);
}
系统事件
Spring系统事件发送顺序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:启动运行中如果发生错误会发送该事件
此处和系统初始化器中的注册的方式完全一致,唯一不同的是:
@SuppressWarnings({ "unchecked", "rawtypes" })
public SpringApplication(ResourceLoader resourceLoader, Class>... primarySources) {
//此方法调用是 注册系统初始化器
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
//此方法调用是 注册系统监听器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
}
监听事件触发机制
- 1
SpringApplication.run(MystuflinkApplication.class, args);
- 2
public static ConfigurableApplicationContext run(Class> primarySource, String... args) {
return run(new Class>[] { primarySource }, args);
}
- 3
public static ConfigurableApplicationContext run(Class>[] primarySources, String[] args) {
return new SpringApplication(primarySources).run(args);
}
- 4
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
ConfigurableApplicationContext context = null;
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
//start事件发布
listeners.starting(bootstrapContext, this.mainApplicationClass);
}
- 5
void starting(ConfigurableBootstrapContext bootstrapContext, Class> mainApplicationClass) {
//调用 (EventPublishingRunListener)listener.starting 方法
doWithListeners("spring.boot.application.starting", (listener) -> listener.starting(bootstrapContext),
(step) -> {
if (mainApplicationClass != null) {
step.tag("mainApplicationClass", mainApplicationClass.getName());
}
});
}
- 6
@Override
public void starting(ConfigurableBootstrapContext bootstrapContext) {
//调用SimpleApplicationEventMulticaster的multicastEvent进行广播事件
this.initialMulticaster
//new 好一个ApplicationStartingEvent事件对象,调用multicastEvent进行广播
.multicastEvent(new ApplicationStartingEvent(bootstrapContext, this.application, this.args));
}
- 7
@Override
public void multicastEvent(ApplicationEvent event) {
multicastEvent(event, resolveDefaultEventType(event));
}
- 8
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
Executor executor = getTaskExecutor();
//getApplicationListeners 方法获取对该event事件感兴趣的监听器,并循环
for (ApplicationListener> listener : getApplicationListeners(event, type)) {
if (executor != null) {
//invokeListener方法进行对循环到的指定的监听器进行广播
executor.execute(() -> invokeListener(listener, event));
}
else {
invokeListener(listener, event);
}
}
}
- 8.1
//获得对event事件感兴趣的监听器
protected Collection> getApplicationListeners(
ApplicationEvent event, ResolvableType eventType) {
//获得该事件的自定义key
ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);
//查看是否有缓存
CachedListenerRetriever existingRetriever = this.retrieverCache.get(cacheKey);
if (existingRetriever != null) {
Collection> result = existingRetriever.getApplicationListeners();
if (result != null) {
//有的话直接返回
return result;
}
}
//否则继续寻找
return retrieveApplicationListeners(eventType, sourceType, newRetriever);
}
- 8.2
private Collection> retrieveApplicationListeners(
ResolvableType eventType, @Nullable Class> sourceType, @Nullable CachedListenerRetriever retriever) {
Set> listeners;
Set listenerBeans;
synchronized (this.defaultRetriever) {
listeners = new linkedHashSet<>(this.defaultRetriever.applicationListeners);
listenerBeans = new linkedHashSet<>(this.defaultRetriever.applicationListenerBeans);
}
for (ApplicationListener> listener : listeners) {
//supportsEvent 判断该监听器是否对该事件感兴趣
if (supportsEvent(listener, eventType, sourceType)) {
if (retriever != null) {
filteredListeners.add(listener);
}
allListeners.add(listener);
}
}
//一般listenerBeans为空,此处不再拓展
if (!listenerBeans.isEmpty()) {
}
}
- 8.3
protected boolean supportsEvent(
ApplicationListener> listener, ResolvableType eventType, @Nullable Class> sourceType) {
//注:GenericApplicationListenerAdapter 是 GenericApplicationListener的接口实现
//注:GenericApplicationListener接口继承自SmartApplicationListener接口
//注:SmartApplicationListener接口继承自 ApplicationListener, Ordered 两个接口
GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ?
(GenericApplicationListener) listener : new GenericApplicationListenerAdapter(listener));
return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType));
}
- 8.4
@Override
@SuppressWarnings("unchecked")
public boolean supportsEventType(ResolvableType eventType) {
if (this.delegate instanceof GenericApplicationListener) {
return ((GenericApplicationListener) this.delegate).supportsEventType(eventType);
}
else if (this.delegate instanceof SmartApplicationListener) {
Class extends ApplicationEvent> eventClass = (Class extends ApplicationEvent>) eventType.resolve();
return (eventClass != null && ((SmartApplicationListener) this.delegate).supportsEventType(eventClass));
}
else {
return (this.declaredEventType == null || this.declaredEventType.isAssignableFrom(eventType));
}
}
- 9
//使用指定的事件触发指定的监听器
protected void invokeListener(ApplicationListener> listener, ApplicationEvent event) {
ErrorHandler errorHandler = getErrorHandler();
if (errorHandler != null) {
try {
//触发调用
doInvokeListener(listener, event);
}
catch (Throwable err) {
errorHandler.handleError(err);
}
}
else {
doInvokeListener(listener, event);
}
}
- 10
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
//监听器onApplicationEvent方法的调用
listener.onApplicationEvent(event);
}
catch (ClassCastException ex) {
}
}
获取监听列表
通用触发条条件
自定义监听器实战
第一种:spring.factories中配置
FirstListener类
import org.springframework.boot.context.event.ApplicationStartedEvent; import org.springframework.context.ApplicationListener; import org.springframework.core.annotation.Order; @Order(1) public class FirstListener implements ApplicationListenerresources目录下新建 : meta-INF/spring.factories{ @Override public void onApplicationEvent(ApplicationStartedEvent event) { System.out.println("FirstListener : hello " + event.getClass()); } }
org.springframework.context.ApplicationListener=com.wwy.myspringboot.customListener.FirstListener第二种:启动类中配置 SecondListener类
import org.springframework.boot.context.event.ApplicationStartedEvent; import org.springframework.context.ApplicationListener; import org.springframework.core.annotation.Order; @Order(2) public class SecondListener implements ApplicationListener启动类{ @Override public void onApplicationEvent(ApplicationStartedEvent event) { System.out.println("SecondListener : hello2 " + event.getClass()); } }
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication springApplication = new SpringApplication(Application.class);
springApplication.addListeners(new SecondListener());
springApplication.run(args);
}
}
第三种:application.properties中配置
ThridListener类
import org.springframework.boot.context.event.ApplicationStartedEvent; import org.springframework.context.ApplicationListener; import org.springframework.core.annotation.Order; @Order(3) public class ThridListener implements ApplicationListenerapplication.properties{ @Override public void onApplicationEvent(ApplicationStartedEvent event) { System.out.println("ThridListener : hello " + event.getClass()); } }
context.listener.classes=com.wwy.myspringboot.customListener.ThridListener第四种:继承SmartApplicationListener,并application.properties中配置 FourthListener类
import org.springframework.boot.context.event.ApplicationPreparedEvent;
import org.springframework.boot.context.event.ApplicationStartedEvent;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.SmartApplicationListener;
import org.springframework.core.annotation.Order;
@Order(4)
public class FourthListener implements SmartApplicationListener {
//注册感兴趣的事件
@Override
public boolean supportsEventType(Class extends ApplicationEvent> eventType) {
return ApplicationStartedEvent.class.isAssignableFrom(eventType) ||
ApplicationPreparedEvent.class.isAssignableFrom(eventType);
}
//接收到事件后的动作
@Override
public void onApplicationEvent(ApplicationEvent event) {
System.out.println("FourthListener : hello " + event.getClass());
}
}
application.properties
context.listener.classes=com.wwy.myspringboot.customListener.ThridListener,com.wwy.myspringboot.customListener.FourthListenerConsole
. ____ _ __ _ _ /\ / ___'_ __ _ _(_)_ __ __ _ ( ( )___ | '_ | '_| | '_ / _` | \/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |___, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.5.5) run FirstInitializer 2021-09-30 23:42:32.480 WARN 3713 --- [ main] o.s.boot.StartupInfoLogger : InetAddress.getLocalHost().getHostName() took 5006 milliseconds to respond. Please verify your network configuration (macOS machines may need to add entries to /etc/hosts). 2021-09-30 23:42:37.491 INFO 3713 --- [ main] c.w.m.customListener.Application : Starting Application using Java 1.8.0_231 on wangwenyong with PID 3713 (/Users/wangwenyong/ideaProject/mystuflink/target/classes started by wangwenyong in /Users/wangwenyong/ideaProject/mystuflink) 2021-09-30 23:42:37.492 INFO 3713 --- [ main] c.w.m.customListener.Application : No active profile set, falling back to default profiles: default FourthListener : hello class org.springframework.boot.context.event.ApplicationPreparedEvent 2021-09-30 23:42:38.028 INFO 3713 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode! 2021-09-30 23:42:38.030 INFO 3713 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data Redis repositories in DEFAULT mode. 2021-09-30 23:42:38.048 INFO 3713 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 7 ms. Found 0 Redis repository interfaces. 2021-09-30 23:42:38.394 INFO 3713 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) 2021-09-30 23:42:38.402 INFO 3713 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2021-09-30 23:42:38.402 INFO 3713 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.53] 2021-09-30 23:42:38.470 INFO 3713 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2021-09-30 23:42:38.470 INFO 3713 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 927 ms 2021-09-30 23:42:39.129 INFO 3713 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' 2021-09-30 23:42:39.138 INFO 3713 --- [ main] c.w.m.customListener.Application : Started Application in 22.035 seconds (JVM running for 27.73) ThridListener : hello class org.springframework.boot.context.event.ApplicationStartedEvent FourthListener : hello class org.springframework.boot.context.event.ApplicationStartedEvent FirstListener : hello class org.springframework.boot.context.event.ApplicationStartedEvent SecondListener : hello2 class org.springframework.boot.context.event.ApplicationStartedEventTIPS
面试问题实现ApplicationListener接口针对单一事件监听
实现SmartApplicationListener接口针对多事件监听
Order值越小越先执行
application.properties中定义的优于其他方式
- 介绍下监听器模式
- SpringBoot关于监听器相关的实现类有哪些
- SpringBoot框架有哪些框架事件以及他们的顺序
- 介绍下监听事件触发机制
- 如何自定义实现系统监听器及注意事项
- 实现ApplicationListener接口与SmartApplicationListener接口区别



