SpringBoot启动过程源码解析(二)--------------- listener.starting及监听模式的实现

上一篇讲了SpringBoot启动过程中, SpringApplication实例化之后,现在正式进入到 SpringApplication.run 方法中,看一看启动过程中,SpringBoot到底做了些什么。 

本篇博客先讲到 listener.starting() , 通过这个方式 讲一讲 监听器设计模式。

先看,Run方法

public ConfigurableApplicationContext run(String... args) {
               // 监控启动过程中耗费时间
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
		ConfigurableApplicationContext context = null;
               // 输出启动过程中的异常
		Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
               // 设置 java.awt.headless , 具体情况另行查阅
		configureHeadlessProperty();
               // 加载 SpringApplicationRunListener
		SpringApplicationRunListeners listeners = getRunListeners(args);
               // 发布事件启动开始事件,广播通知各监听器
		listeners.starting();
		try {
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(
					args);
			ConfigurableEnvironment environment = prepareEnvironment(listeners,
					applicationArguments);
			configureIgnoreBeanInfo(environment);
			Banner printedBanner = printBanner(environment);
			context = createApplicationContext();
			exceptionReporters = getSpringFactoriesInstances(
					SpringBootExceptionReporter.class,
					new Class[] { ConfigurableApplicationContext.class }, context);
			prepareContext(context, environment, listeners, applicationArguments,
					printedBanner);
			refreshContext(context);
			afterRefresh(context, applicationArguments);
			stopWatch.stop();
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass)
						.logStarted(getApplicationLog(), stopWatch);
			}
			listeners.started(context);
			callRunners(context, applicationArguments);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, exceptionReporters, listeners);
			throw new IllegalStateException(ex);
		}

		try {
			listeners.running(context);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, exceptionReporters, null);
			throw new IllegalStateException(ex);
		}
		return context;
	}

先看一个重要的方法 : getRunListeners(args) , 这个方法是从 META-INF/spring.factories文件中加载 SpringApplicationRunListener实现类。目前SpringApplicationRunListener 唯一实现类为EventPublishingRunListener。

private SpringApplicationRunListeners getRunListeners(String[] args) {
                 // 将命令行参数继续往下传递.通过 class 类型加载,根据实例化工厂加载所需类
		Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
		return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
				SpringApplicationRunListener.class, types, this, args));
}

通过实例化工厂, SpringApplicationRunListener.class 类型,再META-INF/spring.factories文件下加载类名,实例化EventPublishingRunListener对象。 加载过程细节已在上一篇种讲述,不再赘述。

接下来就是重要的事件发布方法。 listeners.staring()

SpringApplicationRunListeners维护着一个List<SpringApplicationRunListener>集合,方便统一调用RunListener starting()方法。

我们可以自定义一个Listener 实现 SpringApplicationRunListener接口,并注册到META-INF/spring.factories 自己实现启动过程的事件逻辑。EventPublishingRunListener 作为官方唯一实现类。

EventPublishingRunListener种持有SimleApplicationEventMulticaster对象,用于广播发布事件。

@Override
	public void starting() {
            // 以广播形式发布 ApplicationStaringEvent事件
		this.initialMulticaster.multicastEvent(
				new ApplicationStartingEvent(this.application, this.args));
	}

 

public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
		ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
		for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
			Executor executor = getTaskExecutor();
			if (executor != null) {
				executor.execute(() -> invokeListener(listener, event));
			}
			else {
				invokeListener(listener, event);
			}
		}
	}

  在发布事件种有重要方法, getAppllicationListeners()

protected Collection<ApplicationListener<?>> getApplicationListeners(
			ApplicationEvent event, ResolvableType eventType) {

		Object source = event.getSource();
		Class<?> sourceType = (source != null ? source.getClass() : null);
            // 内部类缓存储存 事件类型
		ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);

		// Quick check for existing entry on ConcurrentHashMap...
            // 先检查缓存中是否存在
		ListenerRetriever retriever = this.retrieverCache.get(cacheKey);
		if (retriever != null) {
			return retriever.getApplicationListeners();
		}

		if (this.beanClassLoader == null ||
				(ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&
						(sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
			// Fully synchronized building and caching of a ListenerRetriever
			synchronized (this.retrievalMutex) {
				retriever = this.retrieverCache.get(cacheKey);
				if (retriever != null) {
					return retriever.getApplicationListeners();
				}
				retriever = new ListenerRetriever(true);
				Collection<ApplicationListener<?>> listeners =
						retrieveApplicationListeners(eventType, sourceType, retriever);
				this.retrieverCache.put(cacheKey, retriever);
				return listeners;
			}
		}
		else {
			// No ListenerRetriever caching -> no synchronization necessary
			return retrieveApplicationListeners(eventType, sourceType, null);
		}
	}

先存缓存中判断是否存在 监听器, 如何没有,调用 retrieveApplicationListeners 方法获取。

 在实例化EventPublishingRunListener 构造函数中,已将SpringApplication 构造函数中加载的10个Listeners 放入ListenerRriever中,并删除了缓存中 retrieveCache中的数据。

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

		List<ApplicationListener<?>> allListeners = new ArrayList<>();
		Set<ApplicationListener<?>> listeners;
		Set<String> listenerBeans;
		synchronized (this.retrievalMutex) {
			listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);
			listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans);
		}
		for (ApplicationListener<?> listener : listeners) {
			if (supportsEvent(listener, eventType, sourceType)) {
				if (retriever != null) {
					retriever.applicationListeners.add(listener);
				}
				allListeners.add(listener);
			}
		}
		if (!listenerBeans.isEmpty()) {
			BeanFactory beanFactory = getBeanFactory();
			for (String listenerBeanName : listenerBeans) {
				try {
					Class<?> listenerType = beanFactory.getType(listenerBeanName);
					if (listenerType == null || supportsEvent(listenerType, eventType)) {
						ApplicationListener<?> listener =
								beanFactory.getBean(listenerBeanName, ApplicationListener.class);
						if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) {
							if (retriever != null) {
								if (beanFactory.isSingleton(listenerBeanName)) {
									retriever.applicationListeners.add(listener);
								}
								else {
									retriever.applicationListenerBeans.add(listenerBeanName);
								}
							}
							allListeners.add(listener);
						}
					}
				}
				catch (NoSuchBeanDefinitionException ex) {
					// Singleton listener instance (without backing bean definition) disappeared -
					// probably in the middle of the destruction phase
				}
			}
		}

通过 ApplicationStartingEvent事件类型,过滤出对一个事件的 监听器,并发布事件。

supportsEvent()方法中。用到适配器设计模式,传入事件类型与监听器进行判断。

protected boolean supportsEvent(
			ApplicationListener<?> listener, ResolvableType eventType, @Nullable Class<?> sourceType) {

		GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ?
				(GenericApplicationListener) listener : new GenericApplicationListenerAdapter(listener));
		return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType));
	}

筛选中出监听器后,调用 invokeListener方法通知监听器,监听器做出相应动作。

 

浅谈监听器模式  : 

监听器模式的三要素:  事件源,事件,监听器 

事件源 : 需要被监听器的对象。

事件: 对事件源的封装。

监听器: 被监听对象改变后,做出相应动作。

 

在启动过程中 ,

SpringApplicaton 就是事件源

ApplicationStartingEvent 是事件 

ApplicationListeners 为监听器 

SpringApplicationRunListener 可以理解成 ListenerManager

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值