springBoot1.5.9.RELEASE啓動源碼分析之SpringApplication#run

1.寫在前面的話,用了SpringBoot也有一年多了,是時候看看它是怎麼啓動的了,廢話不多說,debug模式走起,對於一個菜鳥階段的我,無疑是一段自虐的過程,至於爲什麼選擇1.5.9.RELEASE,因爲公司用的版本就是這個,平時接觸的多,分析工具爲sts版的eclipse,由於啓動過程很漫長,其中比較重要的我會單獨拿出來分析。

2. 啓動類

package com.songhq.zonghe;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@SpringBootApplication
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class ZongHeApplication {

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

}

程序的入口  SpringApplication.run(ZongHeApplication.class, args);

爲了完整的演示,這裏的args我也傳值了 ,如下圖

3.進入SpringApplication 中的靜態方法run   

public static ConfigurableApplicationContext run(Object source, String... args) {
        return run(new Object[] { source }, args);
    }

這裏的source爲ZongHeApplication.class, args 爲 上面傳入的字符串數組

插一段,類名後面加.class是代表什麼呢,這裏用Object接受,那肯定也是一個對象了 ,其實就是Class對象,Class對象會記錄這個類的全名和類加載器等信息

該方法的返回值是ConfigurableApplicationContext對象,那麼我是否粗線的認爲,springBoot啓動的過程就是爲了構造一個ConfigurableApplicationContext對象,

進入 ConfigurableApplicationContext,有點懵逼了,先看看作者對這個接口的解釋吧



SPI interface to be implemented by most if not all application contexts. Provides facilities to configure an application context in addition to the application context client methods in the org.springframework.context.ApplicationContext interface. 

Configuration and lifecycle methods are encapsulated here to avoid making them obvious to ApplicationContext client code. The present methods should only be used by startup and shutdown code.
Since:03.11.2003Author:Juergen HoellerChris Beams

解釋這麼少,估計句句都是精華

先看第一句 SPI interface to be implemented by most if not all application contexts

百度翻譯一下    SPI接口將由大多數(如果不是所有)應用程序上下文實現

又得插一句   SPI接口 ,Service Provider Interface  服務提供接口,具體實現由實現類實現,模塊之間解耦的一種方式,可以說是一種規範吧

再看剩下的大致是說 在ApplicationContext的基礎上,增加了配置工具和生命週期方法,當前方法只能由啓動和關閉代碼使用

關於對ApplicationContext的理解一會會做詳細分析

4.進入重載方法run

public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
		return new SpringApplication(sources).run(args);
	}

5.進入SpringApplication的有參構造方法,再進入initialize(source)方法

    @SuppressWarnings({ "unchecked", "rawtypes" })
	private void initialize(Object[] sources) {
		if (sources != null && sources.length > 0) {
			this.sources.addAll(Arrays.asList(sources));
		}
		this.webEnvironment = deduceWebEnvironment();
		setInitializers((Collection) getSpringFactoriesInstances(
				ApplicationContextInitializer.class));
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		this.mainApplicationClass = deduceMainApplicationClass();
	}

5.1將sources保存在  Set<Object> sources 屬性中

5.2判斷是否爲web環境 初始化 boolean webEnvironment屬性 

”javax.servlet.Servlet","org.springframework.web.context.ConfigurableWebApplicationContext“這連個類都存在則爲web環境

5.3 setInitializers((Collection) getSpringFactoriesInstances( ApplicationContextInitializer.class));

初始化 List<ApplicationContextInitializer<?>> initializers   屬性,至於怎麼獲取這個值得比較複雜

5.3.1,調用 getSpringFactoriesInstances方法,獲取加載器classLoader 

private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type) {
		return getSpringFactoriesInstances(type, new Class<?>[] {});
	}

	private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type,
			Class<?>[] parameterTypes, Object... args) {
		ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
		// Use names and ensure unique to protect against duplicates
		Set<String> names = new LinkedHashSet<String>(
				SpringFactoriesLoader.loadFactoryNames(type, classLoader));
		List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
				classLoader, args, names);
		AnnotationAwareOrderComparator.sort(instances);
		return instances;
	}

5.3.2進入SpringFactoriesLoader.loadFactoryNames(type,classLoader)

public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
		String factoryClassName = factoryClass.getName();
		try {
			Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
					ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
			List<String> result = new ArrayList<String>();
			while (urls.hasMoreElements()) {
				URL url = urls.nextElement();
				Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
				String factoryClassNames = properties.getProperty(factoryClassName);
				result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
			}
			return result;
		}
		catch (IOException ex) {
			throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() +
					"] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex);
		}
	}

factoryClassName的值是 org.springframework.context.ApplicationContextInitializer

classLoader 是 sun.misc.Launcher$AppClassLoader@18b4aac2

回去加載META-INF/spring.factories中的類,比如在遍歷urls,其中的一次url爲

jar:file:/D:/songhaiqiang/code/repository/org/springframework/boot/spring-boot/1.5.9.RELEASE/spring-boot-1.5.9.RELEASE.jar!/META-INF/spring.factories,

接下來就是讀這個文件,該文件的內容如下,\是換行符

# PropertySource Loaders
org.springframework.boot.env.PropertySourceLoader=\
org.springframework.boot.env.PropertiesPropertySourceLoader,\
org.springframework.boot.env.YamlPropertySourceLoader

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

# Application Context Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
org.springframework.boot.context.ContextIdApplicationContextInitializer,\
org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
org.springframework.boot.context.embedded.ServerPortInfoApplicationContextInitializer

# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.context.FileEncodingApplicationListener,\
org.springframework.boot.context.config.AnsiOutputApplicationListener,\
org.springframework.boot.context.config.ConfigFileApplicationListener,\
org.springframework.boot.context.config.DelegatingApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener,\
org.springframework.boot.logging.ClasspathLoggingApplicationListener,\
org.springframework.boot.logging.LoggingApplicationListener

# Environment Post Processors
org.springframework.boot.env.EnvironmentPostProcessor=\
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\
org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor

# Failure Analyzers
org.springframework.boot.diagnostics.FailureAnalyzer=\
org.springframework.boot.diagnostics.analyzer.BeanCurrentlyInCreationFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BeanNotOfRequiredTypeFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BindFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.ConnectorStartFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.NoUniqueBeanDefinitionFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.PortInUseFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.ValidationExceptionFailureAnalyzer

# FailureAnalysisReporters
org.springframework.boot.diagnostics.FailureAnalysisReporter=\
org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter

properties的內容如下 

{org.springframework.boot.diagnostics.FailureAnalyzer=org.springframework.boot.diagnostics.analyzer.BeanCurrentlyInCreationFailureAnalyzer,org.springframework.boot.diagnostics.analyzer.BeanNotOfRequiredTypeFailureAnalyzer,org.springframework.boot.diagnostics.analyzer.BindFailureAnalyzer,org.springframework.boot.diagnostics.analyzer.ConnectorStartFailureAnalyzer,org.springframework.boot.diagnostics.analyzer.NoUniqueBeanDefinitionFailureAnalyzer,org.springframework.boot.diagnostics.analyzer.PortInUseFailureAnalyzer,org.springframework.boot.diagnostics.analyzer.ValidationExceptionFailureAnalyzer, org.springframework.boot.env.EnvironmentPostProcessor=org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor, org.springframework.boot.SpringApplicationRunListener=org.springframework.boot.context.event.EventPublishingRunListener, org.springframework.context.ApplicationContextInitializer=org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,org.springframework.boot.context.ContextIdApplicationContextInitializer,org.springframework.boot.context.config.DelegatingApplicationContextInitializer,org.springframework.boot.context.embedded.ServerPortInfoApplicationContextInitializer, org.springframework.boot.env.PropertySourceLoader=org.springframework.boot.env.PropertiesPropertySourceLoader,org.springframework.boot.env.YamlPropertySourceLoader, org.springframework.context.ApplicationListener=org.springframework.boot.ClearCachesApplicationListener,org.springframework.boot.builder.ParentContextCloserApplicationListener,org.springframework.boot.context.FileEncodingApplicationListener,org.springframework.boot.context.config.AnsiOutputApplicationListener,org.springframework.boot.context.config.ConfigFileApplicationListener,org.springframework.boot.context.config.DelegatingApplicationListener,org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener,org.springframework.boot.logging.ClasspathLoggingApplicationListener,org.springframework.boot.logging.LoggingApplicationListener, org.springframework.boot.diagnostics.FailureAnalysisReporter=org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter}

然後是從中取org.springframework.context.ApplicationContextInitializer得值,可見factoryClassNames爲org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,org.springframework.boot.context.ContextIdApplicationContextInitializer,org.springframework.boot.context.config.DelegatingApplicationContextInitializer,org.springframework.boot.context.embedded.ServerPortInfoApplicationContextInitializer

第二次遍歷的時候又讀到jar:file:/D:/songhaiqiang/code/repository/org/springframework/boot/spring-boot-autoconfigure/1.5.9.RELEASE/spring-boot-autoconfigure-1.5.9.RELEASE.jar!/META-INF/spring.factories

第三次遍歷的時候讀到jar:file:/D:/songhaiqiang/code/repository/org/springframework/spring-beans/4.3.13.RELEASE/spring-beans-4.3.13.RELEASE.jar!/META-INF/spring.factories

結束遍歷返回result 

5.3.3 Set<String> names 得到剛纔去重的org.springframework.context.ApplicationContextInitializer在所有spring.factory文件的值

5.3.4 難道names之後自然獲取創建這些對象,看createSpringFactoriesInstances方法

@SuppressWarnings("unchecked")
	private <T> List<T> createSpringFactoriesInstances(Class<T> type,
			Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args,
			Set<String> names) {
		List<T> instances = new ArrayList<T>(names.size());
		for (String name : names) {
			try {
				Class<?> instanceClass = ClassUtils.forName(name, classLoader);
				Assert.isAssignable(type, instanceClass);
				Constructor<?> constructor = instanceClass
						.getDeclaredConstructor(parameterTypes);
				T instance = (T) BeanUtils.instantiateClass(constructor, args);
				instances.add(instance);
			}
			catch (Throwable ex) {
				throw new IllegalArgumentException(
						"Cannot instantiate " + type + " : " + name, ex);
			}
		}
		return instances;
	}

 這裏沒有什麼好說的通過反射,實例化這些對象

List<T> instances 的值爲[org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer@3ecd23d9, org.springframework.boot.context.ContextIdApplicationContextInitializer@22eeefeb, org.springframework.boot.context.config.DelegatingApplicationContextInitializer@17d0685f, org.springframework.boot.context.embedded.ServerPortInfoApplicationContextInitializer@3891771e, org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer@78ac1102, org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer@2de8284b]

5.3.5,對List<T> instances進行排序AnnotationAwareOrderComparator.sort(instances);

public static void sort(List<?> list) {
		if (list.size() > 1) {
			Collections.sort(list, INSTANCE);
		}
	}

這裏用到了Collections.sort(a,b)方法,排序的字段爲AnnotationAwareOrderComparator這個對象是爲了使用支持@Order註解,

排序後的instances爲[org.springframework.boot.context.config.DelegatingApplicationContextInitializer@17d0685f, org.springframework.boot.context.ContextIdApplicationContextInitializer@22eeefeb, org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer@3ecd23d9, org.springframework.boot.context.embedded.ServerPortInfoApplicationContextInitializer@3891771e, org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer@78ac1102, org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer@2de8284b],順序的確發生了變化

至此 SpringApplication 中private List<ApplicationContextInitializer<?>> initializers初始化成功,

5.4 同理 初始化private List<ApplicationListener<?>> listeners;這個屬性同樣,只不過這次從spring.factory找的鍵爲org.springframework.context.ApplicationListener

5.5 找到main方法所在的類,並賦值給private Class<?> mainApplicationClass; 這裏的值爲 class com.songhq.zonghe.ZongHeApplication

至此  SpringApplication的類初始化任務完成,接下可以到實例化後的run()方法,也就是相當於準備工作做完了,各屬性如下

粘出來如下

addCommandLineProperties    true    
additionalProfiles    HashSet<E>  (id=430)    
applicationContextClass    null    
banner    null    
bannerMode    Banner$Mode  (id=431)    
beanNameGenerator    null    
defaultProperties    null    
environment    null    
headless    true    
initializers    ArrayList<E>  (id=403)    
listeners    ArrayList<E>  (id=426)    
logStartupInfo    true    
mainApplicationClass    Class<T> (com.songhq.zonghe.ZongHeApplication) (id=14)    
registerShutdownHook    true    
resourceLoader    null    
sources    LinkedHashSet<E>  (id=435)    
webEnvironment    true    

這裏一一梳理一下,其中

addCommandLineProperties    private boolean addCommandLineProperties = true;直接賦值的

additionalProfiles  爲[] 還沒有賦值private Set<String> additionalProfiles = new HashSet<String>();

applicationContextClass p rivate Class<? extends ConfigurableApplicationContext> applicationContextClass;爲null 

banner   private Banner banner; 爲null

bannerMode      private Banner.Mode bannerMode = Banner.Mode.CONSOLE; 爲CONSOLE

beanNameGenerator     private BeanNameGenerator beanNameGenerator; 爲null

defaultProperties  private Map<String, Object> defaultProperties; 爲null

environment   private ConfigurableEnvironment environment; 爲null
headless   private boolean headless = true; 爲 true    
initializers   private List<ApplicationContextInitializer<?>> initializers;上面重點介紹了
listeners    private List<ApplicationListener<?>> listeners; 同initializers
logStartupInfo   private boolean logStartupInfo = true; 爲 true    
mainApplicationClass    private Class<?> mainApplicationClass; 爲Class<T> (com.songhq.zonghe.ZongHeApplication) 
registerShutdownHook   private boolean registerShutdownHook = true; 爲 true    
resourceLoader   private ResourceLoader resourceLoader;  null    
sources   private final Set<Object> sources = new LinkedHashSet<Object>();  LinkedHashSet<E>  (id=435) 這個前面也初始化
webEnvironment    private boolean webEnvironment; true    這個也初始化了

小節:new SpringApplication(sources) 初始化了標記爲紅色的五個屬性,至此控制檯沒有任何信息打印出來

6.進入實例化方法public ConfigurableApplicationContext run(String... args) 

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);
		}
	}

一看這方法,也不長啊,心中暗喜,不過一會就不好受了,由於某些方法分析起來比較長,對於複雜的方法,我會專門寫一篇文章介紹

6.1   StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        FailureAnalyzers analyzers = null;

   這幾行代碼很簡單 ,StopWatch 是機率整個代碼耗時的,從start() 到stop(),ConfigurableApplicationContext context = null;
        FailureAnalyzers analyzers = null; 是聲明幾個局部變量名的

6.2 進入 configureHeadlessProperty() 

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

是設置系統參數java.awt.headless的值,如果系統有,則用系統的,如果沒有將他的值設爲this.headless的值  爲true

Headless模式是在缺少顯示屏、鍵盤或者鼠標是的系統配置也比較簡單

6.3進入SpringApplicationRunListeners listeners = getRunListeners(args);

private SpringApplicationRunListeners getRunListeners(String[] args) {
		Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
		return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
				SpringApplicationRunListener.class, types, this, args));
	}

如何實例化spring.factory中的 org.springframework.boot.SpringApplicationRunListener對應的值,與前面的ApplicationContextInitializer流程一樣,只不過,這次調用的不是無參構造,而是有參構造方法,

public EventPublishingRunListener(SpringApplication application, String[] args) {
        this.application = application;
        this.args = args;
        this.initialMulticaster = new SimpleApplicationEventMulticaster();
        for (ApplicationListener<?> listener : application.getListeners()) {
            this.initialMulticaster.addApplicationListener(listener);
        }
    }

有個小插曲com.sun.jdi.ObjectCollectedException occurred while retrieving value  在調試的時候,對象被gc回收了,導致eclipse

報錯,這裏有點懵主要是因爲SpringApplicationRunListeners 和 SpringApplicationRunListener 我靠,能不能區別再小點

SpringApplicationRunListeners  是類, SpringApplicationRunListener  是接口 

而且在 SpringApplicationRunListeners  有這樣一個屬性private final List<SpringApplicationRunListener> listeners; 

而 那個EventPublishingRunListener 是 SpringApplicationRunListener的一個實現類,剛纔那個有參構造就是在初始化這個類

剛開始我也納悶啊,前面initializers 和listeners 的實現類初始化的時候都反射的是無參構造 ,而這個EventPublishingRunListener 初始化的時候要lprivate  SpringApplication application;private final String[] args;這兩個參數幹嘛

原來在爲初始化private final SimpleApplicationEventMulticaster initialMulticaster;這個屬性用的,將springApplication的listeners

傳遞給他來初始化這個屬性

SimpleApplicationEventMulticaster  這個類是幹嘛的呢

看SimpleApplicationEventMulticaster 類的介紹

Simple implementation of the ApplicationEventMulticaster interface.

Multicasts all events to all registered listeners, leaving it up to the listeners to ignore events that they are not interested in. Listeners will usually perform corresponding instanceof checks on the passed-in event object.

By default, all listeners are invoked in the calling thread. This allows the danger of a rogue listener blocking the entire application, but adds minimal overhead. Specify an alternative task executor to have listeners executed in different threads, for example from a thread pool

簡單的翻譯一下:

廣播所有事件到所有註冊的偵聽器,讓偵聽器忽略他們不感興趣的事件。偵聽器通常會對傳入的事件對象執行相應的InstanceOf檢查。

默認情況下,在調用線程中調用所有偵聽器。這允許惡意偵聽器阻塞整個應用程序的危險,但增加的開銷最小。指定另一個任務執行器,使偵聽器在不同的線程中執行,例如從線程池執行

下面的代碼就應該是將已經註冊過的listeners與SimpleApplicationEventMulticast關聯起來

@Override
	public void addApplicationListener(ApplicationListener<?> listener) {
		synchronized (this.retrievalMutex) {
			// 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();
		}
	}

這裏的梳理一下就是SpringApplicationRunListeners中有SpringApplicationRunListener 的實現類 EventPublishingRunListener,

EventPublishingRunListener 中有 SimpleApplicationEventMulticaster ,SimpleApplicationEventMulticaster 有ListenerRetriever

ListenerRetriever有Set<ApplicationListener<?>> applicationListeners,這個applicationListeners即爲 先前在構造Listeners初始化的

6.3進入listeners.starting();其實就是調用 SpringApplicationRunListener 的starting方法

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

 進入實現類中的starting方法,進而調用的SimpleApplicationEventMulticaster 中的multicastEvent方法

@Override
	@SuppressWarnings("deprecation")
	public void starting() {
		this.initialMulticaster
				.multicastEvent(new ApplicationStartedEvent(this.application, this.args));
	}

進入下面的方法ApplicationStartedEvent說是被棄用 而應該使用ApplicationStartingEvent 這個事件,說是啓用了你還自己用,不知道你怎麼想的

@Override
	public void multicastEvent(ApplicationEvent event) {
		multicastEvent(event, resolveDefaultEventType(event));
	}

 

進入multicastEvent(final ApplicationEvent event, ResolvableType eventType)方法

@Override
	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);
			}
		}
	}

其中調用了父類的getApplicationListeners方法

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(eventType, sourceType, retriever); 這個方法

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) {
			listeners = new LinkedHashSet<ApplicationListener<?>>(this.defaultRetriever.applicationListeners);
			listenerBeans = new LinkedHashSet<String>(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) {
								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;
	}

這個方法從註冊的listener中獲取對當前事件感興趣的listener集合,是否感興趣的判斷在supportsEvent(listener, eventType, sourceType)方法中

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));
	}

後來又會調用 GenericApplicationListener  中的 smartListener.supportsEventType(eventType)和smartListener.supportsSourceType(sourceType)方法,而GenericApplicationListener爲接口,即調用實用類中兩種方法

比如這裏的實現類爲org.springframework.boot.context.config.ConfigFileApplicationListener其中的兩個的方法如下

@Override
	public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
		return ApplicationEnvironmentPreparedEvent.class.isAssignableFrom(eventType)
				|| ApplicationPreparedEvent.class.isAssignableFrom(eventType);
	}

	@Override
	public boolean supportsSourceType(Class<?> aClass) {
		return true;
	}

很明顯它只關心 ApplicationEnvironmentPreparedEvent和ApplicationPreparedEvent這連個事件

org.springframework.boot.logging.LoggingApplicationListener就對該事件感興趣

最終篩選,對ApplicationStartedEvent事件敢興趣的有這些listeners

[org.springframework.boot.logging.LoggingApplicationListener@18ce0030, org.springframework.boot.autoconfigure.BackgroundPreinitializer@45b9a632, org.springframework.boot.context.config.DelegatingApplicationListener@25d250c6, org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener@54c562f7]

獲取監聽事件的listener後,就是要執行事件方法了,spring默認啓動多線線程去調用不同的listener中的事件方法,因爲

Executor executor = getTaskExecutor();的executor的值爲null

進入doInvokeListener(listener, event);方法

@SuppressWarnings({"unchecked", "rawtypes"})
	private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
		try {
			listener.onApplicationEvent(event);
		}
		catch (ClassCastException ex) {
			String msg = ex.getMessage();
			if (msg == null || msg.startsWith(event.getClass().getName())) {
				// Possibly a lambda-defined listener which we could not resolve the generic event type for
				Log logger = LogFactory.getLog(getClass());
				if (logger.isDebugEnabled()) {
					logger.debug("Non-matching event type for listener: " + listener, ex);
				}
			}
			else {
				throw ex;
			}
		}
	}

最終調用的是listener中的onApplicationEvent(event)方法,比如 LoggingApplicationListener監聽ApplicationSatartingEvent事件就是初始化日誌的

@Override
	public void onApplicationEvent(ApplicationEvent event) {
		if (event instanceof ApplicationStartingEvent) {
			onApplicationStartingEvent((ApplicationStartingEvent) event);
		}
		else if (event instanceof ApplicationEnvironmentPreparedEvent) {
			onApplicationEnvironmentPreparedEvent(
					(ApplicationEnvironmentPreparedEvent) event);
		}
		else if (event instanceof ApplicationPreparedEvent) {
			onApplicationPreparedEvent((ApplicationPreparedEvent) event);
		}
		else if (event instanceof ContextClosedEvent && ((ContextClosedEvent) event)
				.getApplicationContext().getParent() == null) {
			onContextClosedEvent();
		}
		else if (event instanceof ApplicationFailedEvent) {
			onApplicationFailedEvent();
		}
	}

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

大致看了一下,其他三個listener基本什麼事情都沒幹

至此listeners.starting();執行完畢,大致也就LoggingApplicationListener幹了點事

 

6.4 ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);

這行代碼也比較簡單  構造一個DefaultApplicationArguments 對象 ,這個對象就兩個屬性, args 和source

6.5 ConfigurableEnvironment environment = prepareEnvironment(listeners,applicationArguments);這個方法要注意的是listeners並非SpringApplication中listener ,而是SpringApplicationRunListeners,進入方法

private ConfigurableEnvironment prepareEnvironment(
			SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments) {
		// Create and configure the environment
		ConfigurableEnvironment environment = getOrCreateEnvironment();
		configureEnvironment(environment, applicationArguments.getSourceArgs());
		listeners.environmentPrepared(environment);
		if (!this.webEnvironment) {
			environment = new EnvironmentConverter(getClassLoader())
					.convertToStandardEnvironmentIfNecessary(environment);
		}
		return environment;
	}

6.5.1 進入getOrCreateEnvironment 方法,很明顯 走的是 new StandardServletEnviroment()方法

private ConfigurableEnvironment getOrCreateEnvironment() {
		if (this.environment != null) {
			return this.environment;
		}
		if (this.webEnvironment) {
			return new StandardServletEnvironment();
		}
		return new StandardEnvironment();
	}

 StandardServletEnvironment extends StandardEnvironment 而StandardEnvironment extends AbstractEnvironment

由於子類構造時,會掉父類的構造方法 ,會掉AbstractEnvironment中的構造方法,而在調用customizePropertySources方法時又會調用子類的customizePropertySources方法,即StandardServletEnvironment中的customizePropertySources的方法,

該方法又調用了super.customizePropertySources (),即會調用直接父類中的StandardEnvironment中的customizePropertySources的方法

	public AbstractEnvironment() {
		customizePropertySources(this.propertySources);
		if (logger.isDebugEnabled()) {
			logger.debug("Initialized " + getClass().getSimpleName() + " with PropertySources " + this.propertySources);
		}
	}
@Override
	protected void customizePropertySources(MutablePropertySources propertySources) {
		propertySources.addLast(new StubPropertySource(SERVLET_CONFIG_PROPERTY_SOURCE_NAME));
		propertySources.addLast(new StubPropertySource(SERVLET_CONTEXT_PROPERTY_SOURCE_NAME));
		if (JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable()) {
			propertySources.addLast(new JndiPropertySource(JNDI_PROPERTY_SOURCE_NAME));
		}
		super.customizePropertySources(propertySources);
	}

environment 至此初始化完成 

 6.5.2 configureEnvironment(environment, applicationArguments.getSourceArgs());剛纔是初始化環境,現在纔是配置環境了

protected void configureEnvironment(ConfigurableEnvironment environment,
			String[] args) {
		configurePropertySources(environment, args);
		configureProfiles(environment, args);
	}

沒什麼好講的,進入configurePropertySources方法和configureProfiles方法

protected void configurePropertySources(ConfigurableEnvironment environment,
			String[] args) {
		MutablePropertySources sources = environment.getPropertySources();
		if (this.defaultProperties != null && !this.defaultProperties.isEmpty()) {
			sources.addLast(
					new MapPropertySource("defaultProperties", this.defaultProperties));
		}
		if (this.addCommandLineProperties && args.length > 0) {
			String name = CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME;
			if (sources.contains(name)) {
				PropertySource<?> source = sources.get(name);
				CompositePropertySource composite = new CompositePropertySource(name);
				composite.addPropertySource(new SimpleCommandLinePropertySource(
						name + "-" + args.hashCode(), args));
				composite.addPropertySource(source);
				sources.replace(name, composite);
			}
			else {
				sources.addFirst(new SimpleCommandLinePropertySource(args));
			}
		}
	}

其中會走 source.addFirst()方法去,這裏new SimpleCommandLinePropertySource(args) 最終會調用一下方法

public CommandLineArgs parse(String... args) {
		CommandLineArgs commandLineArgs = new CommandLineArgs();
		for (String arg : args) {
			if (arg.startsWith("--")) {
				String optionText = arg.substring(2, arg.length());
				String optionName;
				String optionValue = null;
				if (optionText.contains("=")) {
					optionName = optionText.substring(0, optionText.indexOf("="));
					optionValue = optionText.substring(optionText.indexOf("=")+1, optionText.length());
				}
				else {
					optionName = optionText;
				}
				if (optionName.isEmpty() || (optionValue != null && optionValue.isEmpty())) {
					throw new IllegalArgumentException("Invalid argument syntax: " + arg);
				}
				commandLineArgs.addOptionArg(optionName, optionValue);
			}
			else {
				commandLineArgs.addNonOptionArg(arg);
			}
		}
		return commandLineArgs;
	}

終於知道--spring.profiles.active=dev是怎麼讀進去的了,最終的效果如圖,添加了一個SimpleCommandLinePropertySource

再進入configureProfiles方法

protected void configureProfiles(ConfigurableEnvironment environment, String[] args) {
		environment.getActiveProfiles(); // ensure they are initialized
		// But these ones should go first (last wins in a property key clash)
		Set<String> profiles = new LinkedHashSet<String>(this.additionalProfiles);
		profiles.addAll(Arrays.asList(environment.getActiveProfiles()));
		environment.setActiveProfiles(profiles.toArray(new String[profiles.size()]));
	}

environment.getActiveProfiles(); 爲激活spring.profiles.active=dev的配置,後面這三行代碼是讀取所有的profiles.active,包括實例化中的springApplication的this.addtionalProfiles

6.5.3 進入listeners.environmentPrepared(environment);方法,再進入listener.environmentPrepared

public void environmentPrepared(ConfigurableEnvironment environment) {
		for (SpringApplicationRunListener listener : this.listeners) {
			listener.environmentPrepared(environment);
		}
	}

 下面的方法在EventPublishingRunListener,很熟悉吧,之前starting()也調用這個類中的方法,很明顯,它又要對外廣播事件

這次廣播的事件爲ApplicationEnvironmentPreparedEvent,字面的意思是環境準備好了,並把環境也傳遞了過去

@Override
	public void environmentPrepared(ConfigurableEnvironment environment) {
		this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(
				this.application, this.args, environment));
	}

我們這裏選擇一個listener的onApplicationEvent方法解讀,這個listener就是 ConfigFileApplicationListener,很明顯會進入到

onApplicationEnvironmentPreparedEvent方法

@Override
	public void onApplicationEvent(ApplicationEvent event) {
		if (event instanceof ApplicationEnvironmentPreparedEvent) {
			onApplicationEnvironmentPreparedEvent(
					(ApplicationEnvironmentPreparedEvent) event);
		}
		if (event instanceof ApplicationPreparedEvent) {
			onApplicationPreparedEvent(event);
		}
	}

下面是具體的方法

private void onApplicationEnvironmentPreparedEvent(
			ApplicationEnvironmentPreparedEvent event) {
		List<EnvironmentPostProcessor> postProcessors = loadPostProcessors();
		postProcessors.add(this);
		AnnotationAwareOrderComparator.sort(postProcessors);
		for (EnvironmentPostProcessor postProcessor : postProcessors) {
			postProcessor.postProcessEnvironment(event.getEnvironment(),
					event.getSpringApplication());
		}
	}

6.5.3.1 分析 List<EnvironmentPostProcessor> postProcessors = loadPostProcessors();這個方法

首次接觸PostProcessor這個詞,是不是很興奮,好像後面還有什麼BeanPostProcessor,第一次遇到,就把他弄清楚一點

EnvironmentPostProcessor,就是個接口,代碼比較少,就全部粘過來了

/*
 * Copyright 2012-2016 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.boot.env;

import org.springframework.boot.SpringApplication;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;

/**
 * Allows for customization of the application's {@link Environment} prior to the
 * application context being refreshed.
 * <p>
 * EnvironmentPostProcessor implementations have to be registered in
 * {@code META-INF/spring.factories}, using the fully qualified name of this class as the
 * key.
 * <p>
 * {@code EnvironmentPostProcessor} processors are encouraged to detect whether Spring's
 * {@link org.springframework.core.Ordered Ordered} interface has been implemented or if
 * the @{@link org.springframework.core.annotation.Order Order} annotation is present and
 * to sort instances accordingly if so prior to invocation.
 *
 * @author Andy Wilkinson
 * @author Stephane Nicoll
 * @since 1.3.0
 */
public interface EnvironmentPostProcessor {

	/**
	 * Post-process the given {@code environment}.
	 * @param environment the environment to post-process
	 * @param application the application to which the environment belongs
	 */
	void postProcessEnvironment(ConfigurableEnvironment environment,
			SpringApplication application);

}

大致的意思是說他可以對環境進行後處理,我的理解就是,初始化的環境將由EnvironmentPostProcessor的實現類進行後處理

繼續ConfigFileApplicationListener同時也實現了EnvironmentPostProcessor這個接口,至此postProcessors 的值爲[org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor@6c64cb25, org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor@6ae5aa72, org.springframework.boot.context.config.ConfigFileApplicationListener@309e345f]

然後是遍歷這幾個EnvironmentPostProcessor的實現類執行裏面的postProcessEnvironment方法

這裏以SpringApplicationJsonEnvironmentPostProcessor爲例

@Override
	public void postProcessEnvironment(ConfigurableEnvironment environment,
			SpringApplication application) {
		String json = environment.resolvePlaceholders(
				"${spring.application.json:${SPRING_APPLICATION_JSON:}}");
		if (StringUtils.hasText(json)) {
			processJson(environment, json);
		}
	}

 

CloudFoundryVcapEnvironmentPostProcessor 中的postProcessEnvironment也沒有幹什麼事,因爲沒有啓用spring cloud

ConfigFileApplicationListener中的postProcessEnvironment,等等,我差點要跳過了,原來這個EnvironmentPostProcessor纔是加載配置文件的關鍵

@Override
	public void postProcessEnvironment(ConfigurableEnvironment environment,
			SpringApplication application) {
		addPropertySources(environment, application.getResourceLoader());
		configureIgnoreBeanInfo(environment);
		bindToSpringApplication(environment, application);
	}

好,我打算單獨寫一篇了 ,地址我都想了 ,嘿嘿  https://blog.csdn.net/weixin_42739473/article/details/98883399

對於ApplicationEnvironmentPreparedEvent這個事件 接下來還有好幾listener  AnsiOutputApplicationListener, LoggingApplicationListener

這裏再看一個LoggingApplicationListener的onApplicationEnviromentPreparedEvent方法

private void onApplicationEnvironmentPreparedEvent(
			ApplicationEnvironmentPreparedEvent event) {
		if (this.loggingSystem == null) {
			this.loggingSystem = LoggingSystem
					.get(event.getSpringApplication().getClassLoader());
		}
		initialize(event.getEnvironment(), event.getSpringApplication().getClassLoader());
	}

再而進入 initialize()

protected void initialize(ConfigurableEnvironment environment,
			ClassLoader classLoader) {
		new LoggingSystemProperties(environment).apply();
		LogFile logFile = LogFile.get(environment);
		if (logFile != null) {
			logFile.applyToSystemProperties();
		}
		initializeEarlyLoggingLevel(environment);
		initializeSystem(environment, this.loggingSystem, logFile);
		initializeFinalLoggingLevels(environment, this.loggingSystem);
		registerShutdownHookIfNecessary(environment, this.loggingSystem);
	}

在 initializeFinalLoggingLevels(environment, this.loggingSystem);得到了控制檯的首次打印日誌

因爲我在application.properties中設置了logging.level.root=level,就是通過這個方法得到的

終於使用日誌打印了,但是是報錯誤日誌

javax.management.InstanceNotFoundException: java.nio:type=Endpoint,name=beansEndpoint,而且還一直打印,影響我走debug啊

具體原因也不太清楚,後來百度好像解決了,解決方法是在java目錄下 jre\lib\security中,在java.policy文件添加

permission javax.management.MBeanTrustPermission "register";

接下來的listener是ClasspathLoggingApplicationListener  BackgroundPreinitializer  DelegatingApplicationListener FileEncodingApplicationListener

這裏再分析一下 FileEncodingApplicationListener,if (resolver.containsProperty("mandatoryFileEncoding"))都沒進去不用分析了

@Override
	public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
		RelaxedPropertyResolver resolver = new RelaxedPropertyResolver(
				event.getEnvironment(), "spring.");
		if (resolver.containsProperty("mandatoryFileEncoding")) {
			String encoding = System.getProperty("file.encoding");
			String desired = resolver.getProperty("mandatoryFileEncoding");
			if (encoding != null && !desired.equalsIgnoreCase(encoding)) {
				logger.error("System property 'file.encoding' is currently '" + encoding
						+ "'. It should be '" + desired
						+ "' (as defined in 'spring.mandatoryFileEncoding').");
				logger.error("Environment variable LANG is '" + System.getenv("LANG")
						+ "'. You could use a locale setting that matches encoding='"
						+ desired + "'.");
				logger.error("Environment variable LC_ALL is '" + System.getenv("LC_ALL")
						+ "'. You could use a locale setting that matches encoding='"
						+ desired + "'.");
				throw new IllegalStateException(
						"The Java Virtual Machine has not been configured to use the "
								+ "desired default character encoding (" + desired
								+ ").");
			}
		}
	}

至此,所有的監聽SpringEnvironmentPreparedEvent的listener中的onApplicationEvent方法都執行過了,終於可以返回主方法了。

6.6 Banner printedBanner = printBanner(environment);進入printBanner方法。

	private Banner printBanner(ConfigurableEnvironment environment) {
		if (this.bannerMode == Banner.Mode.OFF) {
			return null;
		}
		ResourceLoader resourceLoader = this.resourceLoader != null ? this.resourceLoader
				: new DefaultResourceLoader(getClassLoader());
		SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(
				resourceLoader, this.banner);
		if (this.bannerMode == Mode.LOG) {
			return bannerPrinter.print(environment, this.mainApplicationClass, logger);
		}
		return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
	}

6.6.1進入print方法

public Banner print(Environment environment, Class<?> sourceClass, PrintStream out) {
        Banner banner = getBanner(environment, this.fallbackBanner);
        banner.printBanner(environment, sourceClass, out);
        return new PrintedBanner(banner, sourceClass);
    }

期間會去取environment中的 banner.location  banner.text和 banner.image.location屬性,還會調用這個方法

public void printBanner(Environment environment, Class<?> sourceClass,
			PrintStream printStream) {
		for (String line : BANNER) {
			printStream.println(line);
		}
		String version = SpringBootVersion.getVersion();
		version = (version == null ? "" : " (v" + version + ")");
		String padding = "";
		while (padding.length() < STRAP_LINE_SIZE
				- (version.length() + SPRING_BOOT.length())) {
			padding += " ";
		}

		printStream.println(AnsiOutput.toString(AnsiColor.GREEN, SPRING_BOOT,
				AnsiColor.DEFAULT, padding, AnsiStyle.FAINT, version));
		printStream.println();
	}

 以下是SpringBootBanner中的代碼截圖,是不是很熟悉,哈哈,原來他也是一行行的拼接出來的呢

這裏想到自己可以自定義banner.txt文件來取代默認的打印圖案,所以這裏我想一探究竟,這次調試在src/mian/resoures目錄下我添加了banner.txt ,再次debug,進入下面的關鍵方法

String location = environment.getProperty(BANNER_LOCATION_PROPERTY,
				DEFAULT_BANNER_LOCATION);

enviroment.getProperty(a,b);這個方法就是根據a找值,若找不到就返回b,而這裏的b就是“banner.txt”,而且裏面還支持${}這種站位符讀取數據具體就不分析了,核心方法在PropertyPlaceholderHelper這個類中,至此關於banner分析就到這裏了

6.7 進入context = createApplicationContext();,一看這方法就很關鍵

protected ConfigurableApplicationContext createApplicationContext() {
		Class<?> contextClass = this.applicationContextClass;
		if (contextClass == null) {
			try {
				contextClass = Class.forName(this.webEnvironment
						? DEFAULT_WEB_CONTEXT_CLASS : DEFAULT_CONTEXT_CLASS);
			}
			catch (ClassNotFoundException ex) {
				throw new IllegalStateException(
						"Unable create a default ApplicationContext, "
								+ "please specify an ApplicationContextClass",
						ex);
			}
		}
		return (ConfigurableApplicationContext) BeanUtils.instantiate(contextClass);
	}

由於這裏是web環境,spring使用的是AnnotationConfigEmbeddedWebApplicationContext這個上下文的clazz,

return clazz.newInstance();就這樣調用無參構造方法創建ApplicationContext,到這就結束了

6.7 analyzers = new FailureAnalyzers(context);這個是FailureAnalyzers中的構造方法,注意是帶s的而FailureAnalyzer是一個接口,其中loadFailureAnalyzers類似於從spring.factory中讀取Listeners一樣,只不過這個鍵爲org.springframework.boot.diagnostics.FailureAnalyzer,讀到之後根據AnnotationAwareOrderComparator.sort(analyzers);排序,原來spring一貫如此。

FailureAnalyzers(ConfigurableApplicationContext context, ClassLoader classLoader) {
		Assert.notNull(context, "Context must not be null");
		this.classLoader = (classLoader == null ? context.getClassLoader() : classLoader);
		this.analyzers = loadFailureAnalyzers(this.classLoader);
		prepareFailureAnalyzers(this.analyzers, context);
	}

這裏我們看一下prepareFailureAnalyzers這個方法

private void prepareFailureAnalyzers(List<FailureAnalyzer> analyzers,
			ConfigurableApplicationContext context) {
		for (FailureAnalyzer analyzer : analyzers) {
			prepareAnalyzer(context, analyzer);
		}
	}

其中入參analyzers爲[org.springframework.boot.diagnostics.analyzer.BeanCurrentlyInCreationFailureAnalyzer@16150369, org.springframework.boot.diagnostics.analyzer.BeanNotOfRequiredTypeFailureAnalyzer@6b09fb41, org.springframework.boot.diagnostics.analyzer.BindFailureAnalyzer@624ea235, org.springframework.boot.diagnostics.analyzer.ConnectorStartFailureAnalyzer@3932c79a, org.springframework.boot.diagnostics.analyzer.NoUniqueBeanDefinitionFailureAnalyzer@782859e, org.springframework.boot.diagnostics.analyzer.PortInUseFailureAnalyzer@23f5b5dc, org.springframework.boot.diagnostics.analyzer.ValidationExceptionFailureAnalyzer@34bde49d, org.springframework.boot.autoconfigure.diagnostics.analyzer.NoSuchBeanDefinitionFailureAnalyzer@1b1cfb87, org.springframework.boot.autoconfigure.jdbc.DataSourceBeanCreationFailureAnalyzer@821330f, org.springframework.boot.autoconfigure.jdbc.HikariDriverConfigurationFailureAnalyzer@6f43c82]

context爲org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@4b45a2f5: startup date [Thu Jan 01 08:00:00 CST 1970]; root of context hierarchy,就是剛纔我們初始化的AnnotationConfigEmbeddedWebApplicationContext,這裏想必是這些FailureAnalyzer要對context進行處理

private void prepareAnalyzer(ConfigurableApplicationContext context,
			FailureAnalyzer analyzer) {
		if (analyzer instanceof BeanFactoryAware) {
			((BeanFactoryAware) analyzer).setBeanFactory(context.getBeanFactory());
		}
	}

這裏有個BeanFactoryAware接口,如果FailureAnalyzer的實現類也實現了這個接口,就把這個context中的beanfactory賦值給這個這個類

context.getBeanFactory()方法可見context中有beanFactory屬性,就是context包含beanFactory

這裏的beanFactory爲org.springframework.beans.factory.support.DefaultListableBeanFactory,這個prepareAnalyzer就是將初始化的context中的beanFactory與實現BeanFactoryAware的FailureAnalyzer綁定

6.8 prepareContext(context, environment, listeners, applicationArguments,printedBanner); 這個方法很複雜,就單獨整理一篇吧

鏈接地址 https://blog.csdn.net/weixin_42739473/article/details/99290375

6.9 refreshContext(context);,這個方法看書很短,但是極其重要文章地址爲 https://blog.csdn.net/weixin_42739473/article/details/99689335

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章