栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

SpringBoot 启动流程

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

SpringBoot 启动流程

目录
      • SpringApplication的静态run()方法
      • SpringApplication的构造方法
        • 整体流程
        • 设置基础资源 primarySources
        • 推断应用类型 WebApplicationType
        • 设置应用上下文初始化器、应用监听器
        • 推断主类 deduceMainApplicationClass()
      • SpringApplication的实例run()方法
        • 整体流程
        • 计时器 StopWatch
        • spring应用运行监听器 SpringApplicationRunListener
        • 准备环境 prepareEnvironment()
        • 打印Banner printBanner()
        • 创建应用上下文 createApplicationContext()
        • 准备上下文 prepareContext()
      • springboot的启动过程

 

使用的 springboot 源码版本 2.3.12.RELEASE,这是2.3.x系列的最后一个版本。

springboot应用的启动方式很多,可以在引导类中配置 ConfigurableApplicationContext,可以继承 SpringBootServletInitializer 重写SpringApplication的配置…不同的启动方式、不同版本的源码,启动过程、调用的一些方法有所差别,整体过程大同小异,此处以默认的启动方式进行讲述。

 

SpringApplication的静态run()方法

引导类

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
    	//调用 SpringApplication 的静态方法 run() 进行启动
        SpringApplication.run(DemoApplication.class, args);
    }

}

 

实质是调用 SpringApplication 本身的另一个重载的静态 run() 方法

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

这个方法做了2件事

  • 调用 SpringApplication 的构造方法创建 SpringApplication 实例
  • 调用 SpringApplication 实例的run()方法进行启动

这个实例 run() 方法是启动的核心|主要方法

 

springboot的启动思路

  • 核心类是 SpringApplication ,核心方法是 SpringApplication 的实例 run() 方法
  • 调用 SpringApplication 的静态run()方法进行启动,由静态 run() 方法创建 SpringApplication 实例,调用实例的 run() 方法进行启动。

 

SpringApplication的构造方法 整体流程
public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) {
	//设置资源加载器 resourceLoader
	this.resourceLoader = resourceLoader;
	Assert.notNull(primarySources, "PrimarySources must not be null");
	//设置要加载的基础资源 primarySources
	this.primarySources = new linkedHashSet<>(Arrays.asList(primarySources));
	//推断应用类型
	this.webApplicationType = WebApplicationType.deduceFromClasspath();
	//设置应用上下文的初始化器 ApplicationContextInitializer
	setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
	//设置应用监听器 ApplicationListener
	setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
	//推断主类
	this.mainApplicationClass = deduceMainApplicationClass();
}

主要是做一些初始化工作

 

设置基础资源 primarySources
//基础资源
private Set> primarySources;

基础资源是springboot应用中的一些核心类,通常是静态run()方法传入的引导类。所谓的加载基础资源,其实就是处理这些核心类,让这些核心类生效,比如解析引导类上的@SpringBootApplication、@MapperScan,使之生效。

 

推断应用类型 WebApplicationType

枚举类 WebApplicationType

public enum WebApplicationType {

	
	NONE,

	
	SERVLET,

	
	REACTIVE;


	//servlet、reactive的核心类
	
	private static final String[] SERVLET_INDICATOR_CLASSES = { "javax.servlet.Servlet",
			"org.springframework.web.context.ConfigurableWebApplicationContext" };

	private static final String WEBMVC_INDICATOR_CLASS = "org.springframework.web.servlet.DispatcherServlet";

	private static final String WEBFLUX_INDICATOR_CLASS = "org.springframework.web.reactive.DispatcherHandler";

	private static final String JERSEY_INDICATOR_CLASS = "org.glassfish.jersey.servlet.ServletContainer";

	private static final String SERVLET_APPLICATION_CONTEXT_CLASS = "org.springframework.web.context.WebApplicationContext";

	private static final String REACTIVE_APPLICATION_CONTEXT_CLASS = "org.springframework.boot.web.reactive.context.ReactiveWebApplicationContext";


	
	static WebApplicationType deduceFromClasspath() {
		//使用ClassUtils.isPresent()判断 classpath中是否有servlet或reactive的核心类,是否能用类加载器进行加载
		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;
	}


	
	static WebApplicationType deduceFromApplicationContext(Class applicationContextClass) {
		//判断是否是 WebApplicationContext 类或其子类
		if (isAssignable(SERVLET_APPLICATION_CONTEXT_CLASS, applicationContextClass)) {
			return WebApplicationType.SERVLET;
		}
		//判断是否是 ReactiveWebApplicationContext 类或其子类
		if (isAssignable(REACTIVE_APPLICATION_CONTEXT_CLASS, applicationContextClass)) {
			return WebApplicationType.REACTIVE;
		}
		return WebApplicationType.NONE;
	}


	
	private static boolean isAssignable(String target, Class type) {
		try {
			return ClassUtils.resolveClassName(target, null).isAssignableFrom(type);
		}
		catch (Throwable ex) {
			return false;
		}
	}

}

这个枚举类主要

  • 定义了3种应用类型:none、servlet、reactive
  • 提供了2种推断应用类型的方法:deduceFromClasspath 根据classpath中是否对应的核心类进行推断(默认方式)、deduceFromApplicationContext 根据使用的上下文类型进行推断

 

设置应用上下文初始化器、应用监听器

spring.factories 文件格式

#实质是 properties 文件
#key是接口,value指定该接口要使用的实现类,可指定多个实现类,都是使用全限定类名
org.springframework.boot.env.PropertySourceLoader=
org.springframework.boot.env.PropertiesPropertySourceLoader,
org.springframework.boot.env.YamlPropertySourceLoader

 

private List> initializers;

private List> listeners;
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));

都是调用 getSpringFactoriesInstances(),根据 spring.factories 文件中的配置获取指定接口(此处是ApplicationContextInitializer接口、ApplicationListener接口)要使用的实现类,给这些实现类创建实例。

创建的 pplicationContextInitializer、ApplicationListener 实例会赋给 SpringApplication 对应的成员变量保存,以完成这些成员变量的初始化。

 

SpringApplication 的实例方法 getSpringFactoriesInstances()

private  Collection getSpringFactoriesInstances(Class type, Class[] parameterTypes, Object... args) {
	//获取类加载器:如果 this.resourceLoader 不为空则使用resourceLoader的类加载器,否则使用默认的类加载
	ClassLoader classLoader = getClassLoader();
	//加载、解析spring.factories,得到指定接口要使用的各个实现类的全限定类名
	Set names = new linkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
	//通过反射调用构造方法给这些实现类创建实例
	List instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
	AnnotationAwareOrderComparator.sort(instances);
	return instances;
}

 

SpringFactoriesLoader 的静态方法 loadFactoryNames()

public static List loadFactoryNames(Class factoryType, @Nullable ClassLoader classLoader) {
	String factoryTypeName = factoryType.getName();
	//loadSpringFactories()用于加载、解析所有的spring.factories文件,返回 Map>,key是接口,value是该接口要使用的实现类列表
	//getOrDefault()用于从map中获取指定key的value,即指定接口对应的实现类。如果map中没有指定的key,或者对应的value为null,则返回指定的默认值
	return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}



private static Map> loadSpringFactories(@Nullable ClassLoader classLoader) {
	//先从缓存中获取,有就直接返回,没有才加载、解析 spring.factories
	MultiValueMap result = cache.get(classLoader);
	if (result != null) {
		return result;
	}

	try {
		//获取所有jar包中的 meta-INF/spring.factories 文件路径
		Enumeration urls = (classLoader != null ?
				classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
				ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
				
		// linkedMultiValueMap,MultiValue 顾名思义 一个key可以对应多个value
		// 内部用 Map> 存储数据,add(key,value)添加元素时,会把value放到对应的List中
		// 用于存储所有spring.factories文件的解析结果,一个键值对即一个接口的要使用的实现类,key是接口名,值List用于存储该接口要使用的实现类
		result = new linkedMultiValueMap<>();
		
		//遍历所有的spring.factories文件,逐个解析
		while (urls.hasMoreElements()) {
			URL url = urls.nextElement();
			UrlResource resource = new UrlResource(url);
			//解析为Properties
			Properties properties = PropertiesLoaderUtils.loadProperties(resource);
			//遍历各个键值对
			for (Map.Entry entry : properties.entrySet()) {
				//key是接口名
				String factoryTypeName = ((String) entry.getKey()).trim();
				//value是包含多个实现类的字符串,切分为字符串数组进行遍历
				for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
					//添加到 linkedMultiValueMap 中
					result.add(factoryTypeName, factoryImplementationName.trim());
				}
			}
		}
		
		//把所有spring.factories文件的解析结果放到缓存中
		cache.put(classLoader, result);
		//返回解析结果
		return result;
	}
	catch (IOException ex) {
		throw new IllegalArgumentException("Unable to load factories from location [" +
				FACTORIES_RESOURCE_LOCATION + "]", ex);
	}
}

 

显然,第一次调用 getSpringFactoriesInstances() 时,就加载、解析了所有的 spring.factories 文件,把解析结果放到了缓存中,但只实例化了指定接口要使用的实现类。

后续再调用 getSpringFactoriesInstances() 时,直接从缓存中获取解析结果(map),从中获取指定接口的实现类,对其进行实例化,没有再加载、解析spring.factories文件。

 

推断主类 deduceMainApplicationClass()

SpringApplication 的实例方法 deduceMainApplicationClass()

private Class deduceMainApplicationClass() {
	try {
		//获取各个调用的栈帧,一个栈帧对应一个方法调用
		StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
		//遍历这些栈帧
		for (StackTraceElement stackTraceElement : stackTrace) {
			//找到方法名为main的栈帧
			if ("main".equals(stackTraceElement.getMethodName())) {
				//把该栈帧对应的java类作为主类返回
				return Class.forName(stackTraceElement.getClassName());
			}
		}
	}
	catch (ClassNotFoundException ex) {
		// Swallow and continue
	}
	return null;
}

 

SpringApplication的实例run()方法 整体流程

实例run()方法用于启动spring应用,创建并刷新一个新的应用上下文

public ConfigurableApplicationContext run(String... args) {

	//创建StopWatch实例(计时器、秒表),并调用StopWatch实例的start()方法开始计时
	StopWatch stopWatch = new StopWatch();
	stopWatch.start();
	
	ConfigurableApplicationContext context = null;

	//配置系统环境的 java.awt.headless 属性
	configureHeadlessProperty();

	//创建并开启 spring.factories 中指定的所有的 spring应用运行监听器 SpringApplicationRunListener
	SpringApplicationRunListeners listeners = getRunListeners(args);
	listeners.starting();
	
	try {
	
		//构建应用参数:args是main()方法的参数
		ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
		
		//准备环境
		ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
		
		//配置 spring.beaninfo.ignore 属性
		configureIgnoreBeanInfo(environment);
		
		//打印Banner
		Banner printedBanner = printBanner(environment);
		
		//创建应用上下文:通过反射调用应用上下文的构造方法创建实例
		context = createApplicationContext();

		//准备上下文:1、对创建的上下文实例进行配置、初始化,2、配置内置的低级容器,3、加载所有BeanDefinition、完成bean的注册
		prepareContext(context, environment, listeners, applicationArguments, printedBanner);

		//刷新上下文:1、registerShutdownHook() 向jvm注册ShutdownHook关闭钩子,在jvm终止时自动关闭上下文;2、调用应用上下文的 refresh() 方法进行刷新
		refreshContext(context);

		//预留的扩展点,默认为空实现,可在上下文刷新之后做一些自定义的操作
		afterRefresh(context, applicationArguments);

		//终止计时器,打印启动应用花费的时长
		stopWatch.stop();
		if (this.logStartupInfo) {
			//日志示例:Started DemoApplication in 4.25 seconds (JVM running for 5.368)
			new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
		}

		//至此应用已完成启动,执行 SpringApplicationRunListener 的 started() 回调方法
		listeners.started(context);
		
		callRunners(context, applicationArguments);
	}
	catch (Throwable ex) {
		// handleRunFailure()处理异常:
		// 1、如果是非正常退出(exitCode != 0),则发布应用退出事件 ExitCodeEvent,使用异常处理器 SpringBootExceptionHandler 记录退出码 exitCode;
		// 2、执行 SpringApplicationRunListener 的 failed() 回调方法;
		// 3、使用异常报告器 SpringBootExceptionReporter 打印、记录异常信息
		handleRunFailure(context, ex, listeners);
		throw new IllegalStateException(ex);
	}

	try {
		//执行 SpringApplicationRunListener 的 running() 回调方法
		listeners.running(context);
	}
	catch (Throwable ex) {
		//和上面的 handleRunFailure() 差不多,只是传入的运行监听器组是null,不会执行 SpringApplicationRunListener 的 failed() 回调方法
		handleRunFailure(context, ex, null);
		throw new IllegalStateException(ex);
	}
	
	//返回应用上下文
	return context;
}

 

计时器 StopWatch

StopWatch 是spring提供的计时器、秒表,用于统计任务的执行时间

StopWatch stopWatch = new StopWatch();
stopWatch.start();

 

spring应用运行监听器 SpringApplicationRunListener

SpringApplicationRunListener

这个监听器用于监听spring应用的启动事件,即监听 SpringApplication 的实例 run() 方法的执行过程,提供了一系列回调方法,可用于在启动过程中的特定阶段做一些额外操作

public interface SpringApplicationRunListener {

	default void starting() {
	}

	default void environmentPrepared(ConfigurableEnvironment environment) {
	}

	default void contextPrepared(ConfigurableApplicationContext context) {
	}
	
	default void contextLoaded(ConfigurableApplicationContext context) {
	}

	default void started(ConfigurableApplicationContext context) {
	}

	default void running(ConfigurableApplicationContext context) {
	}

	default void failed(ConfigurableApplicationContext context, Throwable exception) {
	}

}

 

SpringApplicationRunListeners 运行监听器组

SpringApplicationRunListener 的复数形式,这个类用于封装多个 SpringApplicationRunListener,提供多个 SpringApplicationRunListener 的批量操作

class SpringApplicationRunListeners {

	private final Log log;

	private final List listeners;

	SpringApplicationRunListeners(Log log, Collection listeners) {
		this.log = log;
		this.listeners = new ArrayList<>(listeners);
	}

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

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

	void contextPrepared(ConfigurableApplicationContext context) {
		for (SpringApplicationRunListener listener : this.listeners) {
			listener.contextPrepared(context);
		}
	}

	void contextLoaded(ConfigurableApplicationContext context) {
		for (SpringApplicationRunListener listener : this.listeners) {
			listener.contextLoaded(context);
		}
	}

	void started(ConfigurableApplicationContext context) {
		for (SpringApplicationRunListener listener : this.listeners) {
			listener.started(context);
		}
	}

	void running(ConfigurableApplicationContext context) {
		for (SpringApplicationRunListener listener : this.listeners) {
			listener.running(context);
		}
	}

	void failed(ConfigurableApplicationContext context, Throwable exception) {
		for (SpringApplicationRunListener listener : this.listeners) {
			callFailedListener(listener, context, exception);
		}
	}

	private void callFailedListener(SpringApplicationRunListener listener, ConfigurableApplicationContext context,
			Throwable exception) {
		//...
	}

}

 

//调用 SpringApplication 本身的 getRunListeners() 方法
SpringApplicationRunListeners listeners = getRunListeners(args);
//开启全部的 SpringApplicationRunListener
listeners.starting();
private SpringApplicationRunListeners getRunListeners(String[] args) {
	Class[] types = new Class[] { SpringApplication.class, String[].class };
	//先调用 getSpringFactoriesInstances(),根据spring.factories中的配置给要使用的SpringApplicationRunListener实现类创建实例
	//再包装为 SpringApplicationRunListeners,以便批量操作所有的 SpringApplicationRunListener 实例
	return new SpringApplicationRunListeners(logger, 
		getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}

 

准备环境 prepareEnvironment()
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
		ApplicationArguments applicationArguments) {
	//获取或创建环境,有现成的环境就直接使用,没有则创建
	ConfigurableEnvironment environment = getOrCreateEnvironment();
	//设置应用参数
	configureEnvironment(environment, applicationArguments.getSourceArgs());
	//绑定配置属性源、环境
	ConfigurationPropertySources.attach(environment);
	//至此环境已配置好,触发所有 SpringApplicationRunListener 的 environmentPrepared() 回调方法
	listeners.environmentPrepared(environment);
	//将配置好的环境绑定到 SpringApplication 上
	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();
	}
}

 

打印Banner printBanner()

Banner接口

@FunctionalInterface
public interface Banner {

	
	void printBanner(Environment environment, Class sourceClass, PrintStream out);

	
	enum Mode {

		
		OFF,

		
		CONSOLE,

		
		LOG

	}

}

 

SpringApplicaition 的 printBanner() 方法

//banner的默认打印模式是输出到控制台
private Banner.Mode bannerMode = Banner.Mode.CONSOLE;


private Banner printBanner(ConfigurableEnvironment environment) {
	if (this.bannerMode == Banner.Mode.OFF) {
		return null;
	}
	ResourceLoader resourceLoader = (this.resourceLoader != null) ? this.resourceLoader
			: new DefaultResourceLoader(null);
	//通过 SpringApplicationBannerPrinter 类打印banner
	SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(resourceLoader, this.banner);
	if (this.bannerMode == Mode.LOG) {
		return bannerPrinter.print(environment, this.mainApplicationClass, logger);
	}
	//console模式的打印
	return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
}

 

SpringApplicationBannerPrinter 类,用于打印banner

class SpringApplicationBannerPrinter {
	
	//banner的配置项
	
	static final String BANNER_LOCATION_PROPERTY = "spring.banner.location";

	static final String BANNER_IMAGE_LOCATION_PROPERTY = "spring.banner.image.location";

	static final String DEFAULT_BANNER_LOCATION = "banner.txt";

	static final String[] IMAGE_EXTENSION = { "gif", "jpg", "png" };
	
	
	private static final Banner DEFAULT_BANNER = new SpringBootBanner();

	private final ResourceLoader resourceLoader;

	private final Banner fallbackBanner;

	SpringApplicationBannerPrinter(ResourceLoader resourceLoader, Banner fallbackBanner) {
		//...
	}

	Banner print(Environment environment, Class sourceClass, Log logger) {
		//...
	}

	Banner print(Environment environment, Class sourceClass, PrintStream out) {
		//...
	}
	
	private Banner getBanner(Environment environment) {
		//...
	}

	
	private Banner getTextBanner(Environment environment) {
		//...
	}

	
	private Banner getImageBanner(Environment environment) {
		//...
	}

	
	private String createStringFromBanner(Banner banner, Environment environment, Class mainApplicationClass)
			throws UnsupportedEncodingException {
		//...
	}


	private static class Banners implements Banner {
		//...
	}

	private static class PrintedBanner implements Banner {
		//...
	}

}

 

创建应用上下文 createApplicationContext()
private Class applicationContextClass;

protected ConfigurableApplicationContext createApplicationContext() {
	//确定要创建的应用上下文类型:如果没有指定应用上下文的类型,则根据推断得到的应用类型自动确定
	Class contextClass = this.applicationContextClass;
	if (contextClass == null) {
		try {
			switch (this.webApplicationType) {
			case SERVLET:
				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);
}

 

准备上下文 prepareContext()

上一步创建应用上下文,只是通过反射调用应用上下文的构造方法创建实例,尚未对上下文实例进行配置。

这一步用于配置创建好的上下文实例,主要包括

  • 配置、初始化应用上下文:给应用上下文设置环境;执行应用上下文的后置处理,给一些尚未填充的属性设置值;执行应用上下文初始化器(ApplicationContextInitializer),对应用上下文进行初始化
  • 打印应用的启动信息
  • 配置内置的低级容器 (至此,高级容器、内置的低级容器都已创建、配置完毕)
  • 加载所有的 BeanDefinition,完成bean的注册
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
		SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
	//设置环境
	context.setEnvironment(environment);
	//执行应用上下文的后置处理,主要是设置一些尚未填充的属性
	postProcessApplicationContext(context);
	//应用初始化器:执行各个应用上下文初始化器(ApplicationContextInitializer)的 shaninitialize() 方法,对上下文进行初始化
	applyInitializers(context);
	//至此上下文准备完毕,执行各个 SpringApplicationRunListener 的 contextPrepared() 回调方法
	listeners.contextPrepared(context);
	
	//如果允许打印启动信息,则
	if (this.logStartupInfo) {
		//打印应用正在启动的信息,示例:Starting DemoApplication on DESKTOP-E74978P with PID 49824
		logStartupInfo(context.getParent() == null);
		//打印 spring.profiles.active 激活的环境,示例:The following profiles are active: test
		logStartupProfileInfo(context);
	}
	
	//获取内置的低级容器,以对内置的低级容器进行一些配置
	ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
	//注册一些特殊的单例bean
	beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
	if (printedBanner != null) {
		beanFactory.registerSingleton("springBootBanner", printedBanner);
	}
	//配置是否允许bean定义覆盖
	if (beanFactory instanceof DefaultListableBeanFactory) {
		((DefaultListableBeanFactory) beanFactory)
				.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
	}
	//配置是否允许bean的懒加载。默认false,高级容器启动时就实例化所有单例
	if (this.lazyInitialization) {
		//如果允许bean的懒加载,则给内置的低级容器添加懒加载对应的后置处理器
		context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
	}
	
	//获取所有的资源,所有的资源指的是 this.primarySources、this.sources 2个属性指定的资源
	Set sources = getAllSources();
	Assert.notEmpty(sources, "Sources must not be empty");
	//加载所有的资源:使用 BeanDefinitionLoader 加载所有的bean定义,完成bean的注册
	load(context, sources.toArray(new Object[0]));
	
	//执行 SpringApplicationRunListener 的 contextLoaded() 回调方法
	listeners.contextLoaded(context);
}



protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
	if (this.beanNameGenerator != null) {
		context.getBeanFactory().registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
				this.beanNameGenerator);
	}
	if (this.resourceLoader != null) {
		if (context instanceof GenericApplicationContext) {
			((GenericApplicationContext) context).setResourceLoader(this.resourceLoader);
		}
		if (context instanceof DefaultResourceLoader) {
			((DefaultResourceLoader) context).setClassLoader(this.resourceLoader.getClassLoader());
		}
	}
	if (this.addConversionService) {
		context.getBeanFactory().setConversionService(ApplicationConversionService.getSharedInstance());
	}
}
 

 

springboot中有两种上下文

1、bootstrap

  • 应用程序的父上下文,先于applicaton加载,且优先级高于applicaton(boostrap设置的属性不会被applicaton覆盖)
  • 主要用于从外部源加载配置,比如springcloud config从配置中心加载配置,以及配置文件的加/解密
     

2、application

  • 应用程序上下文,主要用于自动配置、spring容器相关操作

 

run()方法的执行过程

 

springboot的启动过程

准备阶段

  • 配置 Spring Boot Bean
  • 推断应用类型
  • 推断引导类
  • 加载应用上下文初始器

启动阶段

  • 运行监听器,监听 Spring Boot 事件
  • 创建 Spring 应用上下文

 

自动化装配

转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号