Spring Boot Debug

文章使用的版本为 spring-boot-2.3.4.RELEASE


1. 调用SpringApplicationrun方法

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

2. 进入SpringApplication的run(Class<?> primarySource, String... args)方法

/**
	* Static helper that can be used to run a {@link SpringApplication} from the
	* specified source using default settings.
	* @param primarySource the primary source to load
	* @param args the application arguments (usually passed from a Java main method)
	* @return the running {@link ApplicationContext}
	*/
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
	return run(new Class<?>[] { primarySource }, args);
}

3. 进入SpringApplicationrun(Class<?>[] primarySources, String[] args)方法

/**
	* Static helper that can be used to run a {@link SpringApplication} from the
	* specified sources using default settings and user supplied arguments.
	* @param primarySources the primary sources to load
	* @param args the application arguments (usually passed from a Java main method)
	* @return the running {@link ApplicationContext}
	*/
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
	return new SpringApplication(primarySources).run(args);
}

4. 调用SpringApplication的构造器 SpringApplication(Class<?>... primarySources)

/**
	* Create a new {@link SpringApplication} instance. The application context will load
	* beans from the specified primary sources (see {@link SpringApplication class-level}
	* documentation for details. The instance can be customized before calling
	* {@link #run(String...)}.
	* @param primarySources the primary bean sources
	* @see #run(Class, String[])
	* @see #SpringApplication(ResourceLoader, Class...)
	* @see #setSources(Set)
	*/
public SpringApplication(Class<?>... primarySources) {
	this(null, primarySources);
}

5. 调用SpringApplication的构造器 SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources)

/**
	* Create a new {@link SpringApplication} instance. The application context will load
	* beans from the specified primary sources (see {@link SpringApplication class-level}
	* documentation for details. The instance can be customized before calling
	* {@link #run(String...)}.
	* @param resourceLoader the resource loader to use
	* @param primarySources the primary bean sources
	* @see #run(Class, String[])
	* @see #setSources(Set)
	*/
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
	this.resourceLoader = resourceLoader;
	Assert.notNull(primarySources, "PrimarySources must not be null");
	this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
	this.webApplicationType = WebApplicationType.deduceFromClasspath();
	setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
	setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
	this.mainApplicationClass = deduceMainApplicationClass();
}

ResourceLoader 资源加载器接口,默认实现类DefaultResourceLoader是加载包下所有资源

6. 设置resourceLoader,传入参数值为null

7. 断言检查primarySources参数不能为null

8. 设置primarySources并且用LinkedHashSet去重

9. 设置webApplicationType,由WebApplicationType.deduceFromClasspath()方法得到

static WebApplicationType deduceFromClasspath() {
	if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) 
		&& !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
		&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
			return WebApplicationType.REACTIVE;
		}
		for (String className : SERVLET_INDICATOR_CLASSES) {
			if (!ClassUtils.isPresent(className, null)) {
				return WebApplicationType.NONE;
			}
		}
		return WebApplicationType.SERVLET;
}

WebApplicationType定义了三种类型

1. NONE 当前应用不需要作为一个WEB应用运行,不需要运行嵌入的服务器 2. SERVLET 当前应用需要作为一个servlet web应用运行,需要运行一个嵌入的servlet服务器 3. REACTIVE 当前应用作为一个reactive web应用运行,需要运行一个嵌入的reactive服务器

【reactive web server】响应式服务器,做什么的?面向流的、异步化的,实时流、离线处理领域,spring webflux框架
包含对响应式HTTP、服务器推送、WebSocket的支持,NIO框架,具体的reactive应用后面学习吧

10. 使用ClassUtilsisPresent(String className, @Nullable ClassLoader classLoader)方法判断指定类名的类是否存在

public static boolean isPresent(String className, @Nullable ClassLoader classLoader) {
	try {
		forName(className, classLoader);
		return true;
	}
	catch (IllegalAccessError err) {
		throw new IllegalStateException("Readability mismatch in inheritance hierarchy of class [" +
		className + "]: " + err.getMessage(), err);
	}
	catch (Throwable ex) {
	// Typically ClassNotFoundException or NoClassDefFoundError...
		return false;
	}
}

11. isPresent方法会调用ClassUtilsforName(String name, @Nullable ClassLoader classLoader)方法,尝试加载指定类和指定类的内部类来确定该类是否存在,存在则返回,不存在就抛异常

public static Class<?> forName(String name, @Nullable ClassLoader classLoader)
	throws ClassNotFoundException, LinkageError {

	Assert.notNull(name, "Name must not be null");

	Class<?> clazz = resolvePrimitiveClassName(name);
	if (clazz == null) {
		clazz = commonClassCache.get(name);
	}
	if (clazz != null) {
		return clazz;
	}

	// "java.lang.String[]" style arrays
	if (name.endsWith(ARRAY_SUFFIX)) {
		String elementClassName = name.substring(0, name.length() - ARRAY_SUFFIX.length());
		Class<?> elementClass = forName(elementClassName, classLoader);
		return Array.newInstance(elementClass, 0).getClass();
	}

	// "[Ljava.lang.String;" style arrays
	if (name.startsWith(NON_PRIMITIVE_ARRAY_PREFIX) && name.endsWith(";")) {
		String elementName = name.substring(NON_PRIMITIVE_ARRAY_PREFIX.length(), name.length() - 1);
		Class<?> elementClass = forName(elementName, classLoader);
		return Array.newInstance(elementClass, 0).getClass();
	}

	// "[[I" or "[[Ljava.lang.String;" style arrays
	if (name.startsWith(INTERNAL_ARRAY_PREFIX)) {
		String elementName = name.substring(INTERNAL_ARRAY_PREFIX.length());
		Class<?> elementClass = forName(elementName, classLoader);
		return Array.newInstance(elementClass, 0).getClass();
	}

	ClassLoader clToUse = classLoader;
	if (clToUse == null) {
		clToUse = getDefaultClassLoader();
	}
	try {
		return Class.forName(name, false, clToUse);
	}
	catch (ClassNotFoundException ex) {
		int lastDotIndex = name.lastIndexOf(PACKAGE_SEPARATOR);
		if (lastDotIndex != -1) {
			String innerClassName =
			name.substring(0, lastDotIndex) + INNER_CLASS_SEPARATOR + name.substring(lastDotIndex + 1);
			try {
				return Class.forName(innerClassName, false, clToUse);
			}
			catch (ClassNotFoundException ex2) {
				// Swallow - let original exception get through
			}
		}
		throw ex;
	}
}

12. 回到第5条继续Debug

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
	this.resourceLoader = resourceLoader;
	Assert.notNull(primarySources, "PrimarySources must not be null");
	this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
	this.webApplicationType = WebApplicationType.deduceFromClasspath();
	// debug 下面这句
	setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
	setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
	this.mainApplicationClass = deduceMainApplicationClass();
}

这句是找到SpringFactories里的ApplicationContextInitializer实例,设置上下文初始化器

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

13. 进入下面方法

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

14. 获取类加载器,默认得到的是默认类加载器

15. 进入loadFactoryNames方法

/**
	* Load the fully qualified class names of factory implementations of the
	* given type from {@value #FACTORIES_RESOURCE_LOCATION}, using the given
	* class loader.
	* @param factoryType the interface or abstract class representing the factory
	* @param classLoader the ClassLoader to use for loading resources; can be
	* {@code null} to use the default
	* @throws IllegalArgumentException if an error occurs while loading factory names
	* @see #loadFactories
	*/
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
	String factoryTypeName = factoryType.getName();
	return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}

16. 进入loadSpringFactories方法

private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
	// private static final Map<ClassLoader, MultiValueMap<String, String>> cache = new ConcurrentReferenceHashMap<>();
	MultiValueMap<String, String> result = cache.get(classLoader);
	if (result != null) {
		return result;
	}

	try {
		Enumeration<URL> urls = (classLoader != null ?
		// public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
		classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
		ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
		result = new LinkedMultiValueMap<>();
		while (urls.hasMoreElements()) {
			URL url = urls.nextElement();
			UrlResource resource = new UrlResource(url);
			Properties properties = PropertiesLoaderUtils.loadProperties(resource);
			for (Map.Entry<?, ?> entry : properties.entrySet()) {
				String factoryTypeName = ((String) entry.getKey()).trim();
				for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
					result.add(factoryTypeName, factoryImplementationName.trim());
				}
			}
		}
		cache.put(classLoader, result);
		return result;
	}
	catch (IOException ex) {
		throw new IllegalArgumentException("Unable to load factories from location [" +
		FACTORIES_RESOURCE_LOCATION + "]", ex);
	}
}

这个方法里指定了 Spring Factories 配置存放的路径META-INF/spring.factories,项目关联的jar包都搜了,其中一个的内容如下

# 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

# Error Reporters
org.springframework.boot.SpringBootExceptionReporter=\
org.springframework.boot.diagnostics.FailureAnalyzers

# 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.rsocket.context.RSocketPortInfoApplicationContextInitializer,\
org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer

# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\
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.context.logging.ClasspathLoggingApplicationListener,\
org.springframework.boot.context.logging.LoggingApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener

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

# Failure Analyzers
org.springframework.boot.diagnostics.FailureAnalyzer=\
org.springframework.boot.context.properties.NotConstructorBoundInjectionFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BeanCurrentlyInCreationFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BeanDefinitionOverrideFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BeanNotOfRequiredTypeFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BindFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BindValidationFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.UnboundConfigurationPropertyFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.ConnectorStartFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.NoSuchMethodFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.NoUniqueBeanDefinitionFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.PortInUseFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.ValidationExceptionFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyNameFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyValueFailureAnalyzer

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

方法返回的Map<String,List<String>>就是这个配置文件的内容,这些配置类都要分析一遍

17. 返回15点,第二个方法,Map对象的getOrDefault(Object key, V defaultValue),这是个好方法,平时还没注意到哦,哈哈,菜鸟程序员

public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
	String factoryTypeName = factoryType.getName();
	return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}

18. 继续返回到13点

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
	ClassLoader classLoader = getClassLoader();
	// Use names and ensure unique to protect against duplicates
	Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
	// 接下来Debug下面这句
	List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
	AnnotationAwareOrderComparator.sort(instances);
	return instances;
}

进入createSpringFactoriesInstances方法

private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes,
		ClassLoader classLoader, Object[] args, Set<String> names) {
	List<T> instances = new ArrayList<>(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;
}

这里面又调用了forName,forName是用类加载器尝试加载类,得到Class<?>
下面的instanceClass.getDeclaredConstructor(parameterTypes);里的parameterTypes看看是传的什么?

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

这里是参数初始化的地方,传了个空数组new Class<?>[] {}Class类的getDeclaredConstructor方法找的也是这么个构造器,可变参数是一个任意长度的数组,这个方法找对应参数数组的构造器,通过构造器实例化对象

/**
	* Convenience method to instantiate a class using the given constructor.
	* <p>Note that this method tries to set the constructor accessible if given a
	* non-accessible (that is, non-public) constructor, and supports Kotlin classes
	* with optional parameters and default values.
	* @param ctor the constructor to instantiate
	* @param args the constructor arguments to apply (use {@code null} for an unspecified
	* parameter, Kotlin optional parameters and Java primitive types are supported)
	* @return the new instance
	* @throws BeanInstantiationException if the bean cannot be instantiated
	* @see Constructor#newInstance
	*/
public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
	Assert.notNull(ctor, "Constructor must not be null");
	try {
		ReflectionUtils.makeAccessible(ctor);
	if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(ctor.getDeclaringClass())) {
		return KotlinDelegate.instantiateClass(ctor, args);
	}
	else {
		Class<?>[] parameterTypes = ctor.getParameterTypes();
		Assert.isTrue(args.length <= parameterTypes.length, "Can't specify more arguments than constructor parameters");
		Object[] argsWithDefaultValues = new Object[args.length];
		for (int i = 0 ; i < args.length; i++) {
			if (args[i] == null) {
				Class<?> parameterType = parameterTypes[i];
				argsWithDefaultValues[i] = (parameterType.isPrimitive() ? DEFAULT_TYPE_VALUES.get(parameterType) : null);
			}
			else {
				argsWithDefaultValues[i] = args[i];
			}
		}
	return ctor.newInstance(argsWithDefaultValues);
		}
	}
	catch (InstantiationException ex) {
		throw new BeanInstantiationException(ctor, "Is it an abstract class?", ex);
	}
	catch (IllegalAccessException ex) {
		throw new BeanInstantiationException(ctor, "Is the constructor accessible?", ex);
	}
	catch (IllegalArgumentException ex) {
		throw new BeanInstantiationException(ctor, "Illegal arguments for constructor", ex);
	}
	catch (InvocationTargetException ex) {
		throw new BeanInstantiationException(ctor, "Constructor threw exception", ex.getTargetException());
	}
}

其实只是做一个统一异常处理,哈哈

19. 继续返回到13点

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
	ClassLoader classLoader = getClassLoader();
	// Use names and ensure unique to protect against duplicates
	Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
	List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
	// 接下来Debug下面这句
	AnnotationAwareOrderComparator.sort(instances);
	return instances;
}

这个sor方法主要看AnnotationAwareOrderComparator这个类是做什么比较的了,Debug进去就是一个排序算法

懒得Debug了,搬个砖,随便搜的《详解Spring的核心排序类-AnnotationAwareOrderComparator》

public class AnnotationAwareOrderComparator extends OrderComparator public class OrderComparator implements Comparator<Object>通过这个类,可以对实现了PriorityOrdered、Ordered以及被@Order注解修饰的类进行统一的排序

可以优先加载某些factories类

20. 返回到第5条继续看

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
	this.resourceLoader = resourceLoader;
	Assert.notNull(primarySources, "PrimarySources must not be null");
	this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
	this.webApplicationType = WebApplicationType.deduceFromClasspath();
	// 刚刚在看这儿,继续看
	setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
	setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
	this.mainApplicationClass = deduceMainApplicationClass();
}

这两方法一个是加载Initializer的实例,一个是加载Listener的实例
最后一行,Debug进去

private Class<?> deduceMainApplicationClass() {
	try {
		StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
		for (StackTraceElement stackTraceElement : stackTrace) {
			if ("main".equals(stackTraceElement.getMethodName())) {
				return Class.forName(stackTraceElement.getClassName());
			}
		}
	}
	catch (ClassNotFoundException ex) {
		// Swallow and continue
	}
	return null;
}

这个方法只是找到项目main方法所在的类名

21. 返回到第3点

/**
	* Static helper that can be used to run a {@link SpringApplication} from the
	* specified sources using default settings and user supplied arguments.
	* @param primarySources the primary sources to load
	* @param args the application arguments (usually passed from a Java main method)
	* @return the running {@link ApplicationContext}
	*/
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
	return new SpringApplication(primarySources).run(args);
}

创建了一个SpringApplication实例了,然后运行它的run方法,好像现在才开始进入核心,刚刚的Debug只是加载了一下资源,现在进入run方法

/**
	* Run the Spring application, creating and refreshing a new
	* {@link ApplicationContext}.
	* @param args the application arguments (usually passed from a Java main method)
	* @return a running {@link ApplicationContext}
	*/
public ConfigurableApplicationContext run(String... args) {
	StopWatch stopWatch = new StopWatch();
	stopWatch.start();
	ConfigurableApplicationContext context = null;
	Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
	configureHeadlessProperty();
	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;
}

StopWatch是一个秒表,用来计时的,这应该就是springboot起动是打印的那个启动毫秒时间了,呸,都没算上资源加载时间。

configureHeadlessProperty()设置了系统属性java.awt.headless = true,在系统可能缺少显示设备、键盘或鼠标这些外设的情况下可以运行

getRunListeners又到spring.factories文件里去了,获取了属于SpringApplicationRunListeners的监听类

接着就启动了监听,之前的Initializer和Listener没有启动,就没Debug,这里就需要Debug了

22. 进入SpringApplicationRunListeners.starting()

默认配置的其实就一个监听类EventPublishingRunListener

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

通过Debug变量可以发现EventPublishingRunListenerinitialMulticaster属性里装了13个ApplicationListener

springboot应用debug_服务器


然后就逐个加到Executor里启动监听了。

23. 退出启动监听的Debug,继续返回21点接着看try里的第一行

/**
	* Run the Spring application, creating and refreshing a new
	* {@link ApplicationContext}.
	* @param args the application arguments (usually passed from a Java main method)
	* @return a running {@link ApplicationContext}
	*/
public ConfigurableApplicationContext run(String... args) {
	StopWatch stopWatch = new StopWatch();
	stopWatch.start();
	ConfigurableApplicationContext context = null;
	Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
	configureHeadlessProperty();
	SpringApplicationRunListeners listeners = getRunListeners(args);
	listeners.starting();
	try {
		// 继续Debug这行
		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;
}

第一行是格式化参数,得到键值对和字符串两种参数列表

进入prepareEnvironment方法

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

这是一个准备运行环境的方法
第一行的方法是准备一个服务器环境

private ConfigurableEnvironment getOrCreateEnvironment() {
	if (this.environment != null) {
		return this.environment;
	}
	switch (this.webApplicationType) {
	case SERVLET:
		return new StandardServletEnvironment();
	case REACTIVE:
		return new StandardReactiveWebEnvironment();
	default:
		return new StandardEnvironment();
	}
}

默认值是返回一个servlet服务器环境
返回上一层,进入configureEnvironment方法

/**
 * Template method delegating to
 * {@link #configurePropertySources(ConfigurableEnvironment, String[])} and
 * {@link #configureProfiles(ConfigurableEnvironment, String[])} in that order.
 * Override this method for complete control over Environment customization, or one of
 * the above for fine-grained control over property sources or profiles, respectively.
 * @param environment this application's environment
 * @param args arguments passed to the {@code run} method
 * @see #configureProfiles(ConfigurableEnvironment, String[])
 * @see #configurePropertySources(ConfigurableEnvironment, String[])
 */
protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
	if (this.addConversionService) {
		ConversionService conversionService = ApplicationConversionService.getSharedInstance();
		environment.setConversionService((ConfigurableConversionService) conversionService);
	}
	configurePropertySources(environment, args);
	configureProfiles(environment, args);
}

第一个判断条件,类变量定义初始化值为true
进入下一行,ApplicationConversionService,进入方法就是一个双重校验锁,却没限制单例

/**
 * Returna shared default application {@code ConversionService} instance, lazily
 * building it once needed.
 * <p>
 * Note: This method actually returns an {@link ApplicationConversionService}
 * instance. However, the {@code ConversionService} signature has been preserved for
 * binary compatibility.
 * @return the shared {@code ApplicationConversionService} instance (never
 * {@code null})
 */
public static ConversionService getSharedInstance() {
	ApplicationConversionService sharedInstance = ApplicationConversionService.sharedInstance;
	if (sharedInstance == null) {
		synchronized (ApplicationConversionService.class) {
			sharedInstance = ApplicationConversionService.sharedInstance;
			if (sharedInstance == null) {
				sharedInstance = new ApplicationConversionService();
				ApplicationConversionService.sharedInstance = sharedInstance;
			}
		}
	}
	return sharedInstance;
}

接着进入new ApplicationConversionService()

public ApplicationConversionService() {
	this(null);
}

public ApplicationConversionService(StringValueResolver embeddedValueResolver) {
	if (embeddedValueResolver != null) {
		setEmbeddedValueResolver(embeddedValueResolver);
	}
	configure(this);
}

24. 进入configure(this)

/**
 * Configure the given {@link FormatterRegistry} with formatters and converters
 * appropriate for most Spring Boot applications.
 * @param registry the registry of converters to add to (must also be castable to
 * ConversionService, e.g. being a {@link ConfigurableConversionService})
 * @throws ClassCastException if the given FormatterRegistry could not be cast to a
 * ConversionService
 */
public static void configure(FormatterRegistry registry) {
	DefaultConversionService.addDefaultConverters(registry);
	DefaultFormattingConversionService.addDefaultFormatters(registry);
	addApplicationFormatters(registry);
	addApplicationConverters(registry);
}

25. 进入第一行,注册默认转换器们

/**
 * Add converters appropriate for most environments.
 * @param converterRegistry the registry of converters to add to
 * (must also be castable to ConversionService, e.g. being a {@link ConfigurableConversionService})
 * @throws ClassCastException if the given ConverterRegistry could not be cast to a ConversionService
 */
public static void addDefaultConverters(ConverterRegistry converterRegistry) {
	addScalarConverters(converterRegistry);
	addCollectionConverters(converterRegistry);

	converterRegistry.addConverter(new ByteBufferConverter((ConversionService) converterRegistry));
	converterRegistry.addConverter(new StringToTimeZoneConverter());
	converterRegistry.addConverter(new ZoneIdToTimeZoneConverter());
	converterRegistry.addConverter(new ZonedDateTimeToCalendarConverter());

	converterRegistry.addConverter(new ObjectToObjectConverter());
	converterRegistry.addConverter(new IdToEntityConverter((ConversionService) converterRegistry));
	converterRegistry.addConverter(new FallbackObjectToStringConverter());
	converterRegistry.addConverter(new ObjectToOptionalConverter((ConversionService) converterRegistry));
}

26. 返回上一层,进入第二行DefaultFormattingConversionService.addDefaultFormatters(registry);

/**
 * Add formatters appropriate for most environments: including number formatters,
 * JSR-354 Money & Currency formatters, JSR-310 Date-Time and/or Joda-Time formatters,
 * depending on the presence of the corresponding API on the classpath.
 * @param formatterRegistry the service to register default formatters with
 */
public static void addDefaultFormatters(FormatterRegistry formatterRegistry) {
	// Default handling of number values
	formatterRegistry.addFormatterForFieldAnnotation(new NumberFormatAnnotationFormatterFactory());

	// Default handling of monetary values
	if (jsr354Present) {
		formatterRegistry.addFormatter(new CurrencyUnitFormatter());
		formatterRegistry.addFormatter(new MonetaryAmountFormatter());
		formatterRegistry.addFormatterForFieldAnnotation(new Jsr354NumberFormatAnnotationFormatterFactory());
	}

	// Default handling of date-time values

	// just handling JSR-310 specific date and time types
	new DateTimeFormatterRegistrar().registerFormatters(formatterRegistry);

	if (jodaTimePresent) {
		// handles Joda-specific types as well as Date, Calendar, Long
		new JodaTimeFormatterRegistrar().registerFormatters(formatterRegistry);
	}
	else {
		// regular DateFormat-based Date, Calendar, Long converters
		new DateFormatterRegistrar().registerFormatters(formatterRegistry);
	}
}

27. 返回上一层,进入addApplicationFormatters(registry);addApplicationConverters(registry);

/**
 * Add formatters useful for most Spring Boot applications.
 * @param registry the service to register default formatters with
 */
public static void addApplicationFormatters(FormatterRegistry registry) {
	registry.addFormatter(new CharArrayFormatter());
	registry.addFormatter(new InetAddressFormatter());
	registry.addFormatter(new IsoOffsetFormatter());
}

/**
 * Add converters useful for most Spring Boot applications.
 * @param registry the registry of converters to add to (must also be castable to
 * ConversionService, e.g. being a {@link ConfigurableConversionService})
 * @throws ClassCastException if the given ConverterRegistry could not be cast to a
 * ConversionService
 */
public static void addApplicationConverters(ConverterRegistry registry) {
	addDelimitedStringConverters(registry);
	registry.addConverter(new StringToDurationConverter());
	registry.addConverter(new DurationToStringConverter());
	registry.addConverter(new NumberToDurationConverter());
	registry.addConverter(new DurationToNumberConverter());
	registry.addConverter(new StringToPeriodConverter());
	registry.addConverter(new PeriodToStringConverter());
	registry.addConverter(new NumberToPeriodConverter());
	registry.addConverter(new StringToDataSizeConverter());
	registry.addConverter(new NumberToDataSizeConverter());
	registry.addConverter(new StringToFileConverter());
	registry.addConverter(new InputStreamSourceToByteArrayConverter());
	registry.addConverterFactory(new LenientStringToEnumConverterFactory());
	registry.addConverterFactory(new LenientBooleanToEnumConverterFactory());
}

28. 返回23点,Debug下一行

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
		ApplicationArguments applicationArguments) {
	// Create and configure the environment
	ConfigurableEnvironment environment = getOrCreateEnvironment();
	configureEnvironment(environment, applicationArguments.getSourceArgs());
	// 现在该Debug这了
	ConfigurationPropertySources.attach(environment);
	listeners.environmentPrepared(environment);
	bindToSpringApplication(environment);
	if (!this.isCustomEnvironment) {
		environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
				deduceEnvironmentClass());
	}
	ConfigurationPropertySources.attach(environment);
	return environment;
}

进入attach方法

/**
 * Attach a {@link ConfigurationPropertySource} support to the specified
 * {@link Environment}. Adapts each {@link PropertySource} managed by the environment
 * to a {@link ConfigurationPropertySource} and allows classic
 * {@link PropertySourcesPropertyResolver} calls to resolve using
 * {@link ConfigurationPropertyName configuration property names}.
 * <p>
 * The attached resolver will dynamically track any additions or removals from the
 * underlying {@link Environment} property sources.
 * @param environment the source environment (must be an instance of
 * {@link ConfigurableEnvironment})
 * @see #get(Environment)
 */
public static void attach(Environment environment) {
	Assert.isInstanceOf(ConfigurableEnvironment.class, environment);
	MutablePropertySources sources = ((ConfigurableEnvironment) environment).getPropertySources();
	PropertySource<?> attached = sources.get(ATTACHED_PROPERTY_SOURCE_NAME);
	if (attached != null && attached.getSource() != sources) {
		sources.remove(ATTACHED_PROPERTY_SOURCE_NAME);
		attached = null;
	}
	if (attached == null) {
		sources.addFirst(new ConfigurationPropertySourcesPropertySource(ATTACHED_PROPERTY_SOURCE_NAME,
				new SpringConfigurationPropertySources(sources)));
	}
}

也没什么可看的

29. 返回上一层,Debug下一行

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
		ApplicationArguments applicationArguments) {
	// Create and configure the environment
	ConfigurableEnvironment environment = getOrCreateEnvironment();
	configureEnvironment(environment, applicationArguments.getSourceArgs());
	ConfigurationPropertySources.attach(environment);
	// 现在该Debug这了
	listeners.environmentPrepared(environment);
	bindToSpringApplication(environment);
	if (!this.isCustomEnvironment) {
		environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
				deduceEnvironmentClass());
	}
	ConfigurationPropertySources.attach(environment);
	return environment;
}

这一行也没什么看的,又是准备监听实例,进入下一行

/**
 * Bind the environment to the {@link SpringApplication}.
 * @param environment the environment to bind
 */
protected void bindToSpringApplication(ConfigurableEnvironment environment) {
	try {
		Binder.get(environment).bind("spring.main", Bindable.ofInstance(this));
	}
	catch (Exception ex) {
		throw new IllegalStateException("Cannot bind to SpringApplication", ex);
	}
}

算了,感觉着整个准备环境的方法都不用看了

30. 返回21点

/**
	* Run the Spring application, creating and refreshing a new
	* {@link ApplicationContext}.
	* @param args the application arguments (usually passed from a Java main method)
	* @return a running {@link ApplicationContext}
	*/
public ConfigurableApplicationContext run(String... args) {
	StopWatch stopWatch = new StopWatch();
	stopWatch.start();
	ConfigurableApplicationContext context = null;
	Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
	configureHeadlessProperty();
	SpringApplicationRunListeners listeners = getRunListeners(args);
	listeners.starting();
	try {
		ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
		ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
		// 继续Debug这行
		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;
}

这个进去也没什么可看的,下一行一看就是打印banner了,看一下吧,Debug这么久,控制台终于有消息了

.   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.3.4.RELEASE)

31. 进入createApplicationContext()方法

/**
 * Strategy method used to create the {@link ApplicationContext}. By default this
 * method will respect any explicitly set application context or application context
 * class before falling back to a suitable default.
 * @return the application context (not yet refreshed)
 * @see #setApplicationContextClass(Class)
 */
protected ConfigurableApplicationContext createApplicationContext() {
	Class<?> contextClass = this.applicationContextClass;
	if (contextClass == null) {
		try {
			switch (this.webApplicationType) {
			case SERVLET:
				// class org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext
				contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
				break;
			case REACTIVE:
				contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
				break;
			default:
				contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
			}
		}
		catch (ClassNotFoundException ex) {
			throw new IllegalStateException(
					"Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex);
		}
	}
	return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}

最后一行 通过无参构造器实例化了一个注释里的那个servlet的类

/**
 * Create a new {@link AnnotationConfigServletWebServerApplicationContext} that needs
 * to be populated through {@link #register} calls and then manually
 * {@linkplain #refresh refreshed}.
 */
public AnnotationConfigServletWebServerApplicationContext() {
	this.reader = new AnnotatedBeanDefinitionReader(this);
	this.scanner = new ClassPathBeanDefinitionScanner(this);
}

进去看看

/**
 * Create a new {@code AnnotatedBeanDefinitionReader} for the given registry.
 * <p>If the registry is {@link EnvironmentCapable}, e.g. is an {@code ApplicationContext},
 * the {@link Environment} will be inherited, otherwise a new
 * {@link StandardEnvironment} will be created and used.
 * @param registry the {@code BeanFactory} to load bean definitions into,
 * in the form of a {@code BeanDefinitionRegistry}
 * @see #AnnotatedBeanDefinitionReader(BeanDefinitionRegistry, Environment)
 * @see #setEnvironment(Environment)
 */
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
	this(registry, getOrCreateEnvironment(registry));
}

/**
 * Create a new {@code AnnotatedBeanDefinitionReader} for the given registry,
 * using the given {@link Environment}.
 * @param registry the {@code BeanFactory} to load bean definitions into,
 * in the form of a {@code BeanDefinitionRegistry}
 * @param environment the {@code Environment} to use when evaluating bean definition
 * profiles.
 * @since 3.1
 */
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
	Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
	Assert.notNull(environment, "Environment must not be null");
	this.registry = registry;
	this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
	AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}

1100多行了啊,这种写作方法不太对,应该直接提取关键步骤哦,debug完搞一个,这种方法都看一遍,就怕把@SpringBootApplication整丢了,哈哈哈

/**
 * Register all relevant annotation post processors in the given registry.
 * @param registry the registry to operate on
 * @param source the configuration source element (already extracted)
 * that this registration was triggered from. May be {@code null}.
 * @return a Set of BeanDefinitionHolders, containing all bean definitions
 * that have actually been registered by this call
 */
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
		BeanDefinitionRegistry registry, @Nullable Object source) {

	DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
	if (beanFactory != null) {
		if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
			beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
		}
		if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
			beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
		}
	}

	Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);

	if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
		RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
	}

	if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
		RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
	}

	// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
	if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
		RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
	}

	// Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
	if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
		RootBeanDefinition def = new RootBeanDefinition();
		try {
			def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
					AnnotationConfigUtils.class.getClassLoader()));
		}
		catch (ClassNotFoundException ex) {
			throw new IllegalStateException(
					"Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
		}
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
	}

	if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
		RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
	}

	if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
		RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
	}

	return beanDefs;
}

这个方法return的结果贴一下

springboot应用debug_服务器_02

  1. 回到21点
/**
	* Run the Spring application, creating and refreshing a new
	* {@link ApplicationContext}.
	* @param args the application arguments (usually passed from a Java main method)
	* @return a running {@link ApplicationContext}
	*/
public ConfigurableApplicationContext run(String... args) {
	StopWatch stopWatch = new StopWatch();
	stopWatch.start();
	ConfigurableApplicationContext context = null;
	Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
	configureHeadlessProperty();
	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);
		// 继续Debug这行
		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;
}

进入这个方法,最后到了一个 AbstractApplicationContextrefresh方法

@Override
public void refresh() throws BeansException, IllegalStateException {
	synchronized (this.startupShutdownMonitor) {
		// Prepare this context for refreshing.
		prepareRefresh();

		// Tell the subclass to refresh the internal bean factory.
		ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

		// Prepare the bean factory for use in this context.
		prepareBeanFactory(beanFactory);

		try {
			// Allows post-processing of the bean factory in context subclasses.
			postProcessBeanFactory(beanFactory);

			// Invoke factory processors registered as beans in the context.
			invokeBeanFactoryPostProcessors(beanFactory);

			// Register bean processors that intercept bean creation.
			registerBeanPostProcessors(beanFactory);

			// Initialize message source for this context.
			initMessageSource();

			// Initialize event multicaster for this context.
			initApplicationEventMulticaster();

			// Initialize other special beans in specific context subclasses.
			onRefresh();

			// Check for listener beans and register them.
			registerListeners();

			// Instantiate all remaining (non-lazy-init) singletons.
			finishBeanFactoryInitialization(beanFactory);

			// Last step: publish corresponding event.
			finishRefresh();
		}

		catch (BeansException ex) {
			if (logger.isWarnEnabled()) {
				logger.warn("Exception encountered during context initialization - " +
						"cancelling refresh attempt: " + ex);
			}

			// Destroy already created singletons to avoid dangling resources.
			destroyBeans();

			// Reset 'active' flag.
			cancelRefresh(ex);

			// Propagate exception to caller.
			throw ex;
		}

		finally {
			// Reset common introspection caches in Spring's core, since we
			// might not ever need metadata for singleton beans anymore...
			resetCommonCaches();
		}
	}
}

这个方法很重要啊,执行了IoC容器的初始化,启动了SpringBoot,先搬一些砖放这
《Spring中AbstractApplicationContext的refresh()方法》《SpringBoot源码分析之Spring容器的refresh过程》

嗯,休息一下,马上回来,这个方法信息量有点大,我要清清大脑缓存

第一行的准备,干了几件事,设置开始时间,清除Scanner缓存,校验环境参数等等