springboot源码理解七、run方法执行过程(刷新上下文前的准备阶段)

run方法执行过程(刷新上下文前的准备阶段)


springboot版本:2.2.9.RELEASE。

SpringApplication.run

run方法是springboot启动过程中非常重要的步骤。

SpringBootMytestApplication#main →
SpringApplication#run(java.lang.Class<?>, java.lang.String...) → SpringApplication#run(java.lang.Class<?>[], java.lang.String[]) →
SpringApplication#run(java.lang.String…)

SpringApplication#run(java.lang.String…)

/**
 * 运行spring引用,创建并刷新一个ApplicationContext。
 * 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应用上下文,Spring IoC容器的一种实现。
	ConfigurableApplicationContext context = null;
	Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
	configureHeadlessProperty();
	// 1、获取启动监听器
	SpringApplicationRunListeners listeners = getRunListeners(args);
	listeners.starting();
	try {
		///2、构造上下文环境
		ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
		ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
		configureIgnoreBeanInfo(environment);
		Banner printedBanner = printBanner(environment);
		///3、初始化应用上下文
		context = createApplicationContext();
		exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
				new Class[] { ConfigurableApplicationContext.class }, context);
		// 4、刷新上下文的准备阶段
		prepareContext(context, environment, listeners, applicationArguments, printedBanner);
		// 5、刷新上下文
		refreshContext(context);
		// 6、刷新上下文后的扩展
		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;
}

刷新上下文前的准备阶段

SpringApplication#prepareContext

private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
		SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
	// 设置容器环境
	context.setEnvironment(environment);
	// 执行容器后置处理器
	postProcessApplicationContext(context);
	applyInitializers(context);
	// 向各个监听器发送已准备好的事件
	listeners.contextPrepared(context);
	if (this.logStartupInfo) {
		logStartupInfo(context.getParent() == null);
		logStartupProfileInfo(context);
	}
	// Add boot specific singleton beans
	// Spring IoC容器
	ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
	beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
	if (printedBanner != null) {
		beanFactory.registerSingleton("springBootBanner", printedBanner);
	}
	if (beanFactory instanceof DefaultListableBeanFactory) {
		((DefaultListableBeanFactory) beanFactory)
				.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
	}
	if (this.lazyInitialization) {
		context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
	}
	// Load the sources
	Set<Object> sources = getAllSources();
	Assert.notEmpty(sources, "Sources must not be empty");
	// 加载启动类,注入容器。
	load(context, sources.toArray(new Object[0]));
	listeners.contextLoaded(context);
}

我们看下加载启动类,注入容器这一步。

SpringApplication#load
在这里插入图片描述
SpringApplication#createBeanDefinitionLoader
在这里插入图片描述
org.springframework.boot.BeanDefinitionLoader

/**
 * Create a new {@link BeanDefinitionLoader} that will load beans into the specified
 * {@link BeanDefinitionRegistry}.
 * @param registry the bean definition registry that will contain the loaded beans
 * @param sources the bean sources
 */
BeanDefinitionLoader(BeanDefinitionRegistry registry, Object... sources) {
	Assert.notNull(registry, "Registry must not be null");
	Assert.notEmpty(sources, "Sources must not be empty");
	this.sources = sources;
	// 注解形式的BeanDefinition读取器
	this.annotatedReader = new AnnotatedBeanDefinitionReader(registry);
	// .xml形式的BeanDefinition读取器
	this.xmlReader = new XmlBeanDefinitionReader(registry);
	if (isGroovyPresent()) {
		this.groovyReader = new GroovyBeanDefinitionReader(registry);
	}
	// 范围扫描器
	this.scanner = new ClassPathBeanDefinitionScanner(registry);
	// 扫描器添加排除过滤,在@SpringBootApplication注解exclude属性定义的。
	this.scanner.addExcludeFilter(new ClassExcludeFilter(sources));
}

loader.load()

BeanDefinitionLoader#load()
在这里插入图片描述
BeanDefinitionLoader#load(java.lang.Object)

private int load(Object source) {
	Assert.notNull(source, "Source must not be null");
	// 从Class加载
	if (source instanceof Class<?>) {
		return load((Class<?>) source);
	}
	if (source instanceof Resource) {
		return load((Resource) source);
	}
	if (source instanceof Package) {
		return load((Package) source);
	}
	if (source instanceof CharSequence) {
		return load((CharSequence) source);
	}
	throw new IllegalArgumentException("Invalid source type " + source.getClass());
}

BeanDefinitionLoader#load(java.lang.Class<?>)

private int load(Class<?> source) {
	if (isGroovyPresent() && GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
		// Any GroovyLoaders added in beans{} DSL can contribute beans here
		GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source, GroovyBeanDefinitionSource.class);
		load(loader);
	}
	if (isComponent(source)) {
		// 将启动类的BeanDefinition加载到BeanFactory的map中
		this.annotatedReader.register(source);
		return 1;
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值