Alian解读SpringBoot 2.6.0 源码(二):启动流程分析之监听器解析

一、背景

  上一篇我们讲到SpringApplication对象创建,现在开始SpringApplication的run方法,run方法就不是一句话就能讲完的,不然你也太小看这个框架了,我们需要开始分步解读了,不管总样,我们要先总体上对整个流程有个大概的了解,这不我已经为大家准备好了。

package com.alian.springboot;

import com.alian.springboot.service.HelloWorld;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringbootApplication {

    public static void main(String[] args) {
        SpringApplication.run(HelloWorld.class, args);
    }

}

1.1、run方法整体流程

  接下来的几个方法所在类的具体路径:org.springframework.boot.SpringApplication

	public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
		return run(new Class<?>[] { primarySource }, args);
	}
	
	public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
		return new SpringApplication(primarySources).run(args);
	}

	public ConfigurableApplicationContext run(String... args) {
		// 1、记录启动的开始时间(单位纳秒)
		long startTime = System.nanoTime();
		
		// 2、初始化启动上下文、初始化应用上下文
		DefaultBootstrapContext bootstrapContext = createBootstrapContext();
		ConfigurableApplicationContext context = null;

		// 3、设置无头属性:“java.awt.headless”,默认值为:true(没有图形化界面)
		configureHeadlessProperty();

		// 4、获取所有 Spring 运行监听器
		SpringApplicationRunListeners listeners = getRunListeners(args);
		// 发布应用启动事件
		listeners.starting(bootstrapContext, this.mainApplicationClass);
		try {
			// 5、初始化默认应用参数类(命令行参数)
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);

			// 6、根据运行监听器和应用参数 来准备 Spring 环境
			ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
			// 配置忽略bean信息
			configureIgnoreBeanInfo(environment);

			// 7、创建 Banner 并打印
			Banner printedBanner = printBanner(environment);

			// 8、创建应用上下文
			context = createApplicationContext();
			// 设置applicationStartup
			context.setApplicationStartup(this.applicationStartup);

			// 9、准备应用上下文
			prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);

			// 10、刷新应用上下文(核心)
			refreshContext(context);

			// 11、应用上下文刷新后置处理
			afterRefresh(context, applicationArguments);

			// 13、时间信息、输出日志记录执行主类名
			Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
			}

			// 14、发布应用上下文启动完成事件
			listeners.started(context, timeTakenToStartup);

			// 15、执行所有 Runner 运行器
			callRunners(context, applicationArguments);
		} catch (Throwable ex) {
			// 运行错误处理
			handleRunFailure(context, ex, listeners);
			throw new IllegalStateException(ex);
		}
		try {
			// 16、发布应用上下文就绪事件(可以使用了)
			Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
			listeners.ready(context, timeTakenToReady);
		} catch (Throwable ex) {
			// 运行错误处理
			handleRunFailure(context, ex, null);
			throw new IllegalStateException(ex);
		}
		// 17、返回应用上下文
		return context;
	}

1.2、本文解读范围

  本文主要讲解到监听器的启动,也就是:

	public ConfigurableApplicationContext run(String... args) {
		// 1、记录启动的开始时间(单位纳秒)
		long startTime = System.nanoTime();
		
		// 2、初始化启动上下文、初始化应用上下文
		DefaultBootstrapContext bootstrapContext = createBootstrapContext();
		ConfigurableApplicationContext context = null;

		// 3、设置无头属性:“java.awt.headless”,默认值为:true(没有图形化界面)
		configureHeadlessProperty();

		// 4、获取所有 Spring 运行监听器
		SpringApplicationRunListeners listeners = getRunListeners(args);
		// 发布应用启动事件
		listeners.starting(bootstrapContext, this.mainApplicationClass);
		
		//本文解析到此处,其他代码省略
	}

二、记录应用启动的开始时间

  首先是下面这段代码

	// 1、记录应用程序启动的开始时间(单位纳秒)
	long startTime = System.nanoTime();

  以前的版本(比如 2.5.2)是:

	// 1、创建并启动计时监控类
	StopWatch stopWatch = new StopWatch();
	stopWatch.start();

  哇,相比之前版本的,终于简洁了(一个简单的事,简单处理就好了)!!!这里记录了应用程序启动的开始时间。

三、初始化启动上下文

  接下来是下面这段代码

	// 2、初始化启动上下文、初始化应用上下文
	DefaultBootstrapContext bootstrapContext = createBootstrapContext();
	ConfigurableApplicationContext context = null;

3.1、初始化启动上下文

  此方法所在类的具体路径:org.springframework.boot.SpringApplication

	private DefaultBootstrapContext createBootstrapContext() {
		//创建 DefaultBootstrapContext实例
		DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();
		//遍历列表 列表内容:bootstraptInitializer 注册表初始器
		//每个注册表初始器初始化引导程序上下文
		this.bootstrapRegistryInitializers.forEach((initializer) -> initializer.initialize(bootstrapContext));
		return bootstrapContext;
	}

  从上一篇文章知道并没有获取到启动上下文初始化器,即bootstrapRegistryInitializers的大小为0,也就是没有初始化器执行。我们看下创建 DefaultBootstrapContext实例做了什么,进入 org.springframework.boot.DefaultBootstrapContext

public class DefaultBootstrapContext implements ConfigurableBootstrapContext {

	private final Map<Class<?>, InstanceSupplier<?>> instanceSuppliers = new HashMap<>();

	private final Map<Class<?>, Object> instances = new HashMap<>();
	
	//在里面实例化了一个应用程序事件广播器
	private final ApplicationEventMulticaster events = new SimpleApplicationEventMulticaster();
}

3.2、初始化应用程序事件广播器

  在这里实例化了一个SimpleApplicationEventMulticaster,它继承了抽象类ApplicationEventMulticaster

public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
	public SimpleApplicationEventMulticaster() {
	}
}

  实例化SimpleApplicationEventMulticaster也会对父类进行初始化,我们继续查看ApplicationEventMulticaster 做了什么。

public abstract class AbstractApplicationEventMulticaster
		implements ApplicationEventMulticaster, BeanClassLoaderAware, BeanFactoryAware {
	
	//实例化DefaultListenerRetriever,实际就是一个内部类
	private final DefaultListenerRetriever defaultRetriever = new DefaultListenerRetriever();

	final Map<ListenerCacheKey, CachedListenerRetriever> retrieverCache = new ConcurrentHashMap<>(64);

	//一个内部类
	private class DefaultListenerRetriever {

		public final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<>();

		public final Set<String> applicationListenerBeans = new LinkedHashSet<>();

		public Collection<ApplicationListener<?>> getApplicationListeners() {
			List<ApplicationListener<?>> allListeners = new ArrayList<>(
					this.applicationListeners.size() + this.applicationListenerBeans.size());
			allListeners.addAll(this.applicationListeners);
			if (!this.applicationListenerBeans.isEmpty()) {
				BeanFactory beanFactory = getBeanFactory();
				for (String listenerBeanName : this.applicationListenerBeans) {
					try {
						ApplicationListener<?> listener =
								beanFactory.getBean(listenerBeanName, ApplicationListener.class);
						if (!allListeners.contains(listener)) {
							allListeners.add(listener);
						}
					}
					catch (NoSuchBeanDefinitionException ex) {
						// Singleton listener instance (without backing bean definition) disappeared -
						// probably in the middle of the destruction phase
					}
				}
			}
			AnnotationAwareOrderComparator.sort(allListeners);
			return allListeners;
		}
	}
}

  接下来事件发布时会用到这些:DefaultListenerRetrieverretrieverCacheSimpleApplicationEventMulticaster

3.3、初始化应用上下文

	ConfigurableApplicationContext context = null;

  这里仅仅是定义了这个对象,此这个context 贯穿了整个容器,后续的创建、准备、刷新等等都离不开它,是一个非常核心的容器。

四、设置无头属性

  接下来是下面这段代码

	// 3、设置无头属性:“java.awt.headless”,默认值为:true(没有图形化界面)
	configureHeadlessProperty();

4.1、设置无头属性

  此方法所在类的具体路径:org.springframework.boot.SpringApplication

	private boolean headless = true;//默认值为true
	
	private static final String SYSTEM_PROPERTY_JAVA_AWT_HEADLESS = "java.awt.headless";

	private void configureHeadlessProperty() {
		System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS,
				System.getProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless)));
	}

  给系统属性java.awt.headless设置值,可以自定义设定,如果没有设定则使用默认值true。 java.awt.headless 是J2SE的一种模式,用于在缺少显示屏、键盘或者鼠标时的系统配置,很多监控工具如 jconsole 需要将该值设置为true,但对于服务器来说,可以不需要显示器,所以默认设置为true。

五、创建并发布运行监听器

  最后是下面这段代码,也是本文中最重要的一段了

	// 4、获取所有 Spring 运行监听器
	SpringApplicationRunListeners listeners = getRunListeners(args);
	// 发布应用启动事件
	listeners.starting(bootstrapContext, this.mainApplicationClass);

5.1、获取所有运行监听器

  此方法所在类的具体路径:org.springframework.boot.SpringApplication

public class SpringApplication {

	private static final Log logger = LogFactory.getLog(SpringApplication.class);

	private ApplicationStartup applicationStartup = ApplicationStartup.DEFAULT;

	private SpringApplicationRunListeners getRunListeners(String[] args) {
		Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
		//初始化SpringApplicationRunListeners注意后面有个 s 哦,相当于SpringApplicationRunListener的一个集合
		return new SpringApplicationRunListeners(logger,
				getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args),
				this.applicationStartup);
	}
}

  getSpringFactoriesInstances这个方法相信我们已经很熟悉了,在我们Alian解读SpringBoot 2.6.0 源码(一):SpringApplication对象创建(Spring工厂加载机制)就讲过了。这里获取到了一个事件发布运行监听器:EventPublishingRunListener,我们在spring-boot-2.6.0.jar META-INF/spring.factories 文件中找到如下配置

# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener

  applicationStartup最终就是DefaultApplicationStartup,同时实例化了对象DefaultStartupStep,此对象的方法会在监听器调用starting中的doWithListeners方法用到。初始化SpringApplicationRunListeners注意后面有个 s 哦,相当于SpringApplicationRunListener的一个集合,它包含了运行监听器整个生命周期中执行的方法。

  构造方法所在类的具体路径:org.springframework.boot.SpringApplicationRunListeners

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

5.2、开始启动事件发布运行监听器

  接下里看下运行监听器的启动:

	//运行监听器开始启动
	listeners.starting(bootstrapContext, this.mainApplicationClass);

  此方法所在类的具体路径:org.springframework.boot.SpringApplicationRunListeners,上一步的获取到的事件发布运行监听器,并且也通过构造方法赋值到SpringApplicationRunListeners的属性:private final List<SpringApplicationRunListener> listeners

	private final List<SpringApplicationRunListener> listeners;

	void starting(ConfigurableBootstrapContext bootstrapContext, Class<?> mainApplicationClass) {
		doWithListeners("spring.boot.application.starting", (listener) -> listener.starting(bootstrapContext),
				(step) -> {
					if (mainApplicationClass != null) {
						step.tag("mainApplicationClass", mainApplicationClass.getName());
					}
				});
	}
	//5.1章节中已经讲过了
	private void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction,
			Consumer<StartupStep> stepAction) {
		StartupStep step = this.applicationStartup.start(stepName);
		//遍历运行监听器
		this.listeners.forEach(listenerAction);
		if (stepAction != null) {
			stepAction.accept(step);
		}
		step.end();
	}

  因为我们只获取到了一个运行监听器也就是事件发布运行监听器:EventPublishingRunListener,所以listener.starting(bootstrapContext)就是执行事件发布运行监听器的启动。

5.3、事件发布运行监听器

  我们看下 EventPublishingRunListener starting 方法

public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {

	private final SpringApplication application;

	private final String[] args;

	private final SimpleApplicationEventMulticaster initialMulticaster;

	public EventPublishingRunListener(SpringApplication application, String[] args) {
		this.application = application;
		this.args = args;
		this.initialMulticaster = new SimpleApplicationEventMulticaster();
		for (ApplicationListener<?> listener : application.getListeners()) {
			// 构造方法把之前获取到的监听器(8个)加入到事件广播器中(广播器调用时用到)
			this.initialMulticaster.addApplicationListener(listener);
		}
	}

	@Override
	public void starting(ConfigurableBootstrapContext bootstrapContext) {
		// 通过事件广播器
		this.initialMulticaster
				.multicastEvent(new ApplicationStartingEvent(bootstrapContext, this.application, this.args));
	}
}

  EventPublishingRunListener 的构造方法是很重要的,把之前SpringApplication对象创建时获取到的监听器加入到广播器中,后续广播器会用到,具体见章节5.5

  这里实际调用时通过简单应用程序事件广播器:SimpleApplicationEventMulticaster,并且实例化了一个应用程序启动事件:ApplicationStartingEvent,这里值得一说的是它的父类 SpringApplicationEvent,后续的事件大部分都是跟这个有关。

事件类型说明
ApplicationStartingEvent应用程序开始启动事件
ApplicationEnvironmentPreparedEvent应用程序环境准备事件
ApplicationPreparedEvent应用程序上下文准备事件
ApplicationContextInitializedEvent应用程序容器初始化事件
ApplicationStartedEvent应用程序启动完毕事件
ApplicationReadyEvent应用程序准备就绪事件
ApplicationFailedEvent应用程序失败事件

5.4、事件发布广播器

  方法所在类的具体路径:org.springframework.context.event.SimpleApplicationEventMulticaster

public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {

	@Override
	public void multicastEvent(ApplicationEvent event) {
		// 1、通过事件解析事件类型
		// 2、广播事件
		multicastEvent(event, resolveDefaultEventType(event));
	}

	@Override
	public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
		ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
		// executor默认为null
		Executor executor = getTaskExecutor();
		// 1、根据事件和事件类型获取监听器列表
		// 2、然后遍历监听器列表,分别调用监听器的方法
		for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
			if (executor != null) {
				executor.execute(() -> invokeListener(listener, event));
			} else {
				// 调用
				invokeListener(listener, event);
			}
		}
	}
	
}
  • 首先根据事件解析事件的类型(这里的事件是ApplicationStartingEvent
  • 根据事件和事件类型进行事件广播
  • 根据事件和事件类型获取事件监听器列表(重点

  我们看看根据事件和类型怎么获取符合条件的监听器,也就是 getApplicationListeners(event, type) 方法。

5.5、获取符合事件的监听器

  这里调用getApplicationListeners方法,实际就是调用抽象类AbstractApplicationEventMulticaster中的getApplicationListeners方法。

	protected Collection<ApplicationListener<?>> getApplicationListeners(
			ApplicationEvent event, ResolvableType eventType) {
		// event为ApplicationStartingEvent
		// event里面的source就是SpringApplication,是在实例化ApplicationStartingEvent时赋值的
		Object source = event.getSource();
		Class<?> sourceType = (source != null ? source.getClass() : null);
		
		// 静态内部类,也就是根据 event 类型和 source 类型构造出来的对象
		ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);
		
		// 要填充的CachedListenerRetriever 
		CachedListenerRetriever newRetriever = null;

		// 此时是为null,retrieverCache在初始化应用程序事件广播器就初始化好了(见小章节3.2)
		// retrieverCache用于存储监听器,变量的定义如下,它的键是 ListenerCacheKey,值是 CachedListenerRetriever
		CachedListenerRetriever existingRetriever = this.retrieverCache.get(cacheKey);
		if (existingRetriever == null) {
			// 不存则缓存 new ListenerRetriever
			if (this.beanClassLoader == null || (ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&
							(sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
				// 初始化CachedListenerRetriever
				newRetriever = new CachedListenerRetriever();
				// putIfAbsent   如果传入key对应的value已经存在,就返回存在的value,不进行替换。
				// 如果不存在,就添加key和value,返回null
				// 此处不存在,返回null
				existingRetriever = this.retrieverCache.putIfAbsent(cacheKey, newRetriever);
				if (existingRetriever != null) {
					newRetriever = null;  // no need to populate it in retrieveApplicationListeners
				}
			}
		}
		// 此时existingRetriever 为null
		if (existingRetriever != null) {
			Collection<ApplicationListener<?>> result = existingRetriever.getApplicationListeners();
			if (result != null) {
				return result;
			}
			// If result is null, the existing retriever is not fully populated yet by another thread.
			// Proceed like caching wasn't possible for this current local attempt.
		}
		return retrieveApplicationListeners(eventType, sourceType, newRetriever);
	}
  • event 里面的source就是SpringApplication,是在实例化ApplicationStartingEvent 时赋值的
  • ListenerCacheKey 根据 event 类型和 source 类型构造出来的对象
  • retrieverCache 用于存储监听器,它的键是 ListenerCacheKey,值是 CachedListenerRetriever
  • existingRetriever 是已缓存的监听器

  我们继续跟进 retrieveApplicationListeners 方法

	private Collection<ApplicationListener<?>> retrieveApplicationListeners(
			ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable CachedListenerRetriever retriever) {

		List<ApplicationListener<?>> allListeners = new ArrayList<>();
		Set<ApplicationListener<?>> filteredListeners = (retriever != null ? new LinkedHashSet<>() : null);
		Set<String> filteredListenerBeans = (retriever != null ? new LinkedHashSet<>() : null);

		Set<ApplicationListener<?>> listeners;
		Set<String> listenerBeans;
		synchronized (this.defaultRetriever) {
			// this.defaultRetriever.applicationListeners的值是通过实例化EventPublishingRunListener时通过构造方法加入的
			listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);
			// listenerBeans是为空
			listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans);
		}
		// Add programmatically registered listeners, including ones coming
		// from ApplicationListenerDetector (singleton beans and inner beans).
		// 从实例化EventPublishingRunListener我们知道加入到广播器的一共有8个
		for (ApplicationListener<?> listener : listeners) {
			// 根据event类型source类型对listener进行匹配判断
			if (supportsEvent(listener, eventType, sourceType)) {
				if (retriever != null) {
					filteredListeners.add(listener);
				}
				// 匹配上了就加入列表
				allListeners.add(listener);
			}
		}
		// 最终allListeners结果是3个:BackgroundPreinitializer、DelegatingApplicationListener、LoggingApplicationListener

		// Add listeners by bean name, potentially overlapping with programmatically
		// registered listeners above - but here potentially with additional metadata.
		// listenerBeans为空
		if (!listenerBeans.isEmpty()) {
			ConfigurableBeanFactory beanFactory = getBeanFactory();
			for (String listenerBeanName : listenerBeans) {
				try {
					if (supportsEvent(beanFactory, listenerBeanName, eventType)) {
						ApplicationListener<?> listener = beanFactory.getBean(listenerBeanName, ApplicationListener.class);
						if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) {
							if (retriever != null) {
								if (beanFactory.isSingleton(listenerBeanName)) {
									filteredListeners.add(listener);
								} else {
									filteredListenerBeans.add(listenerBeanName);
								}
							}
							allListeners.add(listener);
						}
					} else {
						// Remove non-matching listeners that originally came from
						// ApplicationListenerDetector, possibly ruled out by additional
						// BeanDefinition metadata (e.g. factory method generics) above.
						Object listener = beanFactory.getSingleton(listenerBeanName);
						if (retriever != null) {
							filteredListeners.remove(listener);
						}
						allListeners.remove(listener);
					}
				} catch (NoSuchBeanDefinitionException ex) {
					// Singleton listener instance (without backing bean definition) disappeared -
					// probably in the middle of the destruction phase
				}
			}
		}
		// 匹配后的监听器排序
		AnnotationAwareOrderComparator.sort(allListeners);
		// retriever此时有ApplicationStartingEvent
		if (retriever != null) {
			if (filteredListenerBeans.isEmpty()) {
				// 把匹配的监听器存储下来(为3个)
				retriever.applicationListeners = new LinkedHashSet<>(allListeners);
				retriever.applicationListenerBeans = filteredListenerBeans;
			} else {
				retriever.applicationListeners = filteredListeners;
				retriever.applicationListenerBeans = filteredListenerBeans;
			}
		}
		// 返回结果
		return allListeners;
	}

  方法是挺长的,但是调试下来的逻辑也比较清晰,一个比较关键地方是

	listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);

  这里的 this.defaultRetriever.applicationListeners 的值是通过实例化 EventPublishingRunListener 对象时的构造方法加入的,因为比较关键我们再次提一下

	private final SimpleApplicationEventMulticaster initialMulticaster;
	
	public EventPublishingRunListener(SpringApplication application, String[] args) {
		this.application = application;
		this.args = args;
		this.initialMulticaster = new SimpleApplicationEventMulticaster();
		for (ApplicationListener<?> listener : application.getListeners()) {
			//把监听器加入到广播器中,一共8个
			this.initialMulticaster.addApplicationListener(listener);
		}
	}

  方法所在类的具体路径:org.springframework.context.event.AbstractApplicationEventMulticaster,有一个添加监听器的方法: addApplicationListener

public abstract class AbstractApplicationEventMulticaster
		implements ApplicationEventMulticaster, BeanClassLoaderAware, BeanFactoryAware {
		
	@Override
	public void addApplicationListener(ApplicationListener<?> listener) {
		synchronized (this.defaultRetriever) {
			// Explicitly remove target for a proxy, if registered already,
			// in order to avoid double invocations of the same listener.
			Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);
			if (singletonTarget instanceof ApplicationListener) {
				this.defaultRetriever.applicationListeners.remove(singletonTarget);
			}
			//此处加入的
			this.defaultRetriever.applicationListeners.add(listener);
			this.retrieverCache.clear();
		}
	}
}

  另外这个8个监听器需要进行过滤,只有 event 类型和 source 类型匹配的才符合,最终是三个匹配:

  • BackgroundPreinitializer
  • DelegatingApplicationListener
  • LoggingApplicationListener

5.6、事件匹配

  那么这三个是怎么匹配的呢?通过 supportsEvent 方法实现的。

	protected boolean supportsEvent(
			ApplicationListener<?> listener, ResolvableType eventType, @Nullable Class<?> sourceType) {
		// 判断监听器是否是GenericApplicationListener 的一个实例
		// 是,转为GenericApplicationListener 实例
		// 不是,通过适配器GenericApplicationListenerAdapter来处理
		GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ?
				(GenericApplicationListener) listener : new GenericApplicationListenerAdapter(listener));
		// 只有event类型和source类型都匹配才返回true
		return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType));
	}
  • 判断监听器是否是GenericApplicationListener 的一个实例
  • 是,转为GenericApplicationListener 实例,不是,通过适配器GenericApplicationListenerAdapter来处理
  • 对event类型和source类型分别进行匹配判断

  先看一个ApplicationStartingEvent的类图
在这里插入图片描述

监听器对应的事件
AnsiOutputApplicationListenerApplicationEnvironmentPreparedEvent
BackgroundPreinitializerSpringApplicationEvent
ClearCachesApplicationListenerContextRefreshedEvent
DelegatingApplicationListenerApplicationEvent
EnvironmentPostProcessorApplicationListenerApplicationEnvironmentPreparedEvent、ApplicationPreparedEvent、ApplicationFailedEvent
FileEncodingApplicationListenerApplicationEnvironmentPreparedEvent
LoggingApplicationListenerApplicationStartingEvent、ApplicationEnvironmentPreparedEvent、ApplicationPreparedEvent、 ContextClosedEvent、ApplicationFailedEvent
ParentContextCloserApplicationListenerParentContextAvailableEvent

  其中ApplicationContextInitializedEvent、ApplicationStartingEvent、ApplicationEnvironmentPreparedEvent、ApplicationPreparedEvent、 ApplicationReadyEvent、ApplicationStartedEvent、ApplicationFailedEvent 这7个是继承SpringApplicationEvent,而 SpringApplicationEvent 继承 ApplicationEvent,属性源都是SpringApplication时,满足自身事件或父类的都会匹配上。

  结合这8个监听器的对应的事件,我们可以知道满足 ApplicationStartingEvent 的就只有上面标红的三个监听器。具体匹配判断也是根据这些来的,大家可以debug看下,我就不一个个调试显示了。

5.7、监听器执行

  方法所在类的具体路径:org.springframework.context.event.SimpleApplicationEventMulticaster

public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {

	// 使用给定的事件调用给定的监听器
	protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
		// ErrorHandler 默认为null
		ErrorHandler errorHandler = getErrorHandler();
		if (errorHandler != null) {
			try {
				doInvokeListener(listener, event);
			} catch (Throwable err) {
				errorHandler.handleError(err);
			}
		} else {
			// 调用
			doInvokeListener(listener, event);
		}
	}

	@SuppressWarnings({"rawtypes", "unchecked"})
	private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
		try {
			// 调用监听器的onApplicationEvent方法
			listener.onApplicationEvent(event);
		} catch (ClassCastException ex) {
			String msg = ex.getMessage();
			if (msg == null || matchesClassCastMessage(msg, event.getClass()) ||
					(event instanceof PayloadApplicationEvent &&
							matchesClassCastMessage(msg, ((PayloadApplicationEvent) event).getPayload().getClass()))) {
				// Possibly a lambda-defined listener which we could not resolve the generic event type for
				// -> let's suppress the exception.
				Log loggerToUse = this.lazyLogger;
				if (loggerToUse == null) {
					loggerToUse = LogFactory.getLog(getClass());
					this.lazyLogger = loggerToUse;
				}
				if (loggerToUse.isTraceEnabled()) {
					loggerToUse.trace("Non-matching event type for listener: " + listener, ex);
				}
			} else {
				throw ex;
			}
		}
	}
}
  • 遍历监听器列表,执行 invokeListener(listener, event)
  • doInvokeListener(listener, event)
  • 调用监听器的onApplicationEvent(event)方法

  我们在上一小节就说到了只有3个符合条件的监听器,它们都会执行它们的 onApplicationEvent ,不过这三个监听器只有LoggingApplicationListener干了点事,其他两个相当于啥也没有干,大家也可以调试看下,后面会单用一篇文章解读LoggingApplicationListener

结语

  本文解读了最新版springboot监听器解析的源码,SpringApplicationRunListenersstarting也是很重要的一个流程,后续environmentPrepared、prepareContext,contextLoaded,started,ready都是一样的流程,所以大家一定要掌握,对你了解SpringBoot启动流程有很大的帮助。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值