欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

三、Springboot源码解析:SpringApplication#run(1)

程序员文章站 2022-07-07 11:20:01
...

创建完SpringApplication对象之后,接下来就是调用其run方法了,源码如下:

	public ConfigurableApplicationContext run(String... args) {
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
		ConfigurableApplicationContext context = null;
		FailureAnalyzers analyzers = null;
		//即便没有显示器,也允许其启动
		configureHeadlessProperty();
		SpringApplicationRunListeners listeners = getRunListeners(args);
		listeners.starting();
		try {
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(
					args);
			ConfigurableEnvironment environment = prepareEnvironment(listeners,
					applicationArguments);
			Banner printedBanner = printBanner(environment);
			context = createApplicationContext();
			analyzers = new FailureAnalyzers(context);
			prepareContext(context, environment, listeners, applicationArguments,
					printedBanner);
			refreshContext(context);
			afterRefresh(context, applicationArguments);
			listeners.finished(context, null);
			stopWatch.stop();
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass)
						.logStarted(getApplicationLog(), stopWatch);
			}
			return context;
		}
		catch (Throwable ex) {
			handleRunFailure(context, listeners, analyzers, ex);
			throw new IllegalStateException(ex);
		}
	}

一步一步看吧。

一、StopWatch

这是一个秒表,用于记录程序的耗时时间,源码非常简单,一个StopWatch代表一组任务(taskList),其中有一个内部类TaskInfo代表一组任务中的某一个任务,内部类中记录了该任务的耗时时间和任务名称,用法如下:
三、Springboot源码解析:SpringApplication#run(1)

二、获取SpringApplicationRunListeners

那么问题又来了,什么是SpringApplicationRunListeners?如何获取的?该类的注释写的非常好:Listener for the SpringApplication run method. SpringApplicationRunListeners are loaded via the SpringFactoriesLoader and should declare a public constructor that accepts a SpringApplication instance and a String[] of arguments. A new SpringApplicationRunListener instance will be created for each run.意思就是该类是SpringApplication类中run方法的监听器,SpringApplicationRunListeners和ApplicationContextInitializer、ApplicationListener一样是通过SpringFactoriesLoader在spring.factories中获取的。debug了一下源代码,发现只有spring-boot-1.5.8.RELEASE.jar的spring.factories有org.springframework.boot.SpringApplicationRunListener对应的值:org.springframework.boot.context.event.EventPublishingRunListener,而SpringApplicationRunListeners表示的是SpringApplicationRunListener的集合,该集合的长度为1。
接下来会执行listeners.starting()这段代码:

public void starting() {
		for (SpringApplicationRunListener listener : this.listeners) {
			listener.starting();
		}
	}

接着调用SpringApplicationRunListener的starting方法,按照上面我们说的,此处SpringApplicationRunListener对应的实现类为org.springframework.boot.context.event.EventPublishingRunListener,那就来看看它的starting方法是什么样的:

public void starting() {
	this.initialMulticaster
			.multicastEvent(new ApplicationStartedEvent(this.application, this.args));
}

从代码的命名来看,像是一个组播器initialMulticaster发布了一个ApplicationStartedEvent事件,在真正发布事件之前,会先将事件解析为ResolvableType,流程图如下:三、Springboot源码解析:SpringApplication#run(1)
从代码来看,就是根据ApplicationStartedEvent构造出来一个ResolvableType,什么是ResolvableType呢:三、Springboot源码解析:SpringApplication#run(1)
其实对于它的定位就是一个反射的工具类,可以让我们更方便地获取类的信息,解析完这个事件之后,就要真正发布事件了:三、Springboot源码解析:SpringApplication#run(1)
我们看到,在真正发布事件之前,会先调用图5中的方法,获取与该事件匹配的监听器,代码如下:

final Map<ListenerCacheKey, ListenerRetriever> retrieverCache =
			new ConcurrentHashMap<ListenerCacheKey, ListenerRetriever>(64);
private Object retrievalMutex = this.defaultRetriever;
private final ListenerRetriever defaultRetriever = new ListenerRetriever(false);
private Object retrievalMutex = this.defaultRetriever;
			
protected Collection<ApplicationListener<?>> getApplicationListeners(
			ApplicationEvent event, ResolvableType eventType) {
	//获取事件源
	Object source = event.getSource();
	Class<?> sourceType = (source != null ? source.getClass() : null);
	//由下面代码的命名可以大致猜测出,这一部分的代码想使用缓存,而下面的一行代码就是创建一个缓存键,ListenerCacheKey类是本类的一个内部类
	ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);

	// Quick check for existing entry on ConcurrentHashMap...
	//ListenerRetriever是该类中的一个变量,数据结构为ConcurrentHashMap
	//获取上一个cacheKey对应的ListenerRetriever,ListenerRetriever是该类的一个内部类,retrieve的意思是检索,
	ListenerRetriever retriever = this.retrieverCache.get(cacheKey);
	//此处retriever的值为null,所以if方法体的代码不会被执行
	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
		//retrievalMutex是该类的一个变量,它的值为ListenerRetriever的一个实例对象,它有一个属性Set<ApplicationListener<?>> applicationListeners的值为SpringApplication对象中存储的所有ApplicationListener,一共10个,该ListenerRetriever对象该属性的初始化是发生在实例化EventPublishingRunListener对象是赋值的。
		synchronized (this.retrievalMutex) {
			//retriever是该类的一个变量,值为一个空的ConcurrentHashMap,此处get的结果为null
			retriever = this.retrieverCache.get(cacheKey);
			if (retriever != null) {
				return retriever.getApplicationListeners();
			}
			//新建一个ListenerRetriever
			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);
	}
}

private Collection<ApplicationListener<?>> retrieveApplicationListeners(
			ResolvableType eventType, Class<?> sourceType, ListenerRetriever retriever) {
	//存放所有的监听器
	LinkedList<ApplicationListener<?>> allListeners = new LinkedList<ApplicationListener<?>>();
	Set<ApplicationListener<?>> listeners;
	Set<String> listenerBeans;
	synchronized (this.retrievalMutex) {
		//把上面我们提到的10个监听器赋值给listeners
		listeners = new LinkedHashSet<ApplicationListener<?>>(this.defaultRetriever.applicationListeners);
		//listenerBeans初始化,集合内没有元素,因为applicationListenerBeans的长度为0
		listenerBeans = new LinkedHashSet<String>(this.defaultRetriever.applicationListenerBeans);
	}
	for (ApplicationListener<?> listener : listeners) {
		//判断是否是符合该listener的时间
		if (supportsEvent(listener, eventType, sourceType)) {
			if (retriever != null) {
				//添加符合条件的listener
				retriever.applicationListeners.add(listener);
			}
			allListeners.add(listener);
		}
	}
	if (!listenerBeans.isEmpty()) {
		//获取BeanFactory
		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) {
							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
			}
		}
	}
	AnnotationAwareOrderComparator.sort(allListeners);
	return allListeners;
}

protected boolean supportsEvent(ApplicationListener<?> listener, ResolvableType eventType, Class<?> sourceType) {
	GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ?
			(GenericApplicationListener) listener : new GenericApplicationListenerAdapter(listener));
	return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType));
}

对于上面代码,这里做一个简单总结,在初始化SpringApplication对象的时候,我们初始化了一个监听器对象列表,这里通过getApplicationListeners(event, type)筛选出监听应用启动事件的监听器,一共有四个:三、Springboot源码解析:SpringApplication#run(1)
然后就是发布事件了:

public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
	ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
	//获取匹配该事件的监听器
	for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
		//获取线程执行器
		Executor executor = getTaskExecutor();
		//发布应用启动事件
		if (executor != null) {
			executor.execute(new Runnable() {
				@Override
				public void run() {
					invokeListener(listener, event);
				}
			});
		}
		else {
			invokeListener(listener, event);
		}
	}
}

接下来分别执行这四个监听器的onApplicationEvent方法,它们分别做了什么事呢?
1、LoggingApplicationListener

private LoggingSystem loggingSystem;
private void onApplicationStartingEvent(ApplicationStartingEvent event) {
	this.loggingSystem = LoggingSystem
			.get(event.getSpringApplication().getClassLoader());
	this.loggingSystem.beforeInitialize();
}

从代码来看,应该是初始化日志系统,因为这里不涉及比较核心的东西,就一笔带过。
2、BackgroundPreinitializer

	@Override
	public void onApplicationEvent(SpringApplicationEvent event) {
		if (event instanceof ApplicationEnvironmentPreparedEvent) {
			if (preinitializationStarted.compareAndSet(false, true)) {
				performPreinitialization();
			}
		}
		if ((event instanceof ApplicationReadyEvent
				|| event instanceof ApplicationFailedEvent)
				&& preinitializationStarted.get()) {
			try {
				preinitializationComplete.await();
			}
			catch (InterruptedException ex) {
				Thread.currentThread().interrupt();
			}
		}
	}

debug了一下发现,上面的方法体中if的条件均不满足,没有执行任何实质性的代码。
3、DelegatingApplicationListener

	public void onApplicationEvent(ApplicationEvent event) {
		if (event instanceof ApplicationEnvironmentPreparedEvent) {
			List<ApplicationListener<ApplicationEvent>> delegates = getListeners(
					((ApplicationEnvironmentPreparedEvent) event).getEnvironment());
			if (delegates.isEmpty()) {
				return;
			}
			this.multicaster = new SimpleApplicationEventMulticaster();
			for (ApplicationListener<ApplicationEvent> listener : delegates) {
				this.multicaster.addApplicationListener(listener);
			}
		}
		if (this.multicaster != null) {
			this.multicaster.multicastEvent(event);
		}
	}

和上一步一样,什么都没执行。
4、LiquibaseServiceLocatorApplicationListener

	public void onApplicationEvent(ApplicationStartingEvent event) {
		if (ClassUtils.isPresent("liquibase.servicelocator.ServiceLocator", null)) {
			new LiquibasePresent().replaceServiceLocator();
		}
	}

也没做什么实质的东西,这里主要就是看下类路径有没有liquibase.servicelocator.ServiceLocator这个类,如果有就替换一下,猜想可能是为了修复什么漏洞而添加的一个监听器。

三、总结

本篇主要介绍了如下几个要点:

  • 启动StopWatch
  • 从spring.factories中获取SpringApplicationRunListeners的实例,该监听器可以理解为整个run方法的监听器,调用它的starting方法,发布一个ApplicationStartedEvent事件
  • 从SpringApplication中所有的监听器中筛选出监听改事件的监听器,一共筛选出了四个
  • 筛选出的四个监听器分别响应该事件,只有LoggingApplicationListener做了一些实质性的工作,那就是日志系统的初始化。

四、the next…

解析以下三行代码:

  • ApplicationArguments applicationArguments = new DefaultApplicationArguments(
    args);
  • ConfigurableEnvironment environment = prepareEnvironment(listeners,
    applicationArguments);
  • Banner printedBanner = printBanner(environment);