SpringBoot源码-spring boot启动入口ruan方法主线分析(二)

12.刷新前操作

java 复制代码
 // 刷新前操作
  prepareContext(context, environment, listeners, applicationArguments, printedBanner);

进入prepareContext

java 复制代码
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
		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);
	}
复制代码
***applyInitializers(context);实现细节如下***:
bash 复制代码
	protected void applyInitializers(ConfigurableApplicationContext context) {
		for (ApplicationContextInitializer initializer : getInitializers()) {
			Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
					ApplicationContextInitializer.class);
			Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
			initializer.initialize(context);
		}
	}

getInitializers获取的就是SpringApplication构造函数里的这7个,然后循环调用initialize方法。

bash 复制代码
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener

# 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

七个ApplicationContextInitializer执行完毕之后,增加了两个bfpp,三个listeners

SharedMetadataReaderFactoryContextInitializer:

java 复制代码
	@Override
	public void initialize(ConfigurableApplicationContext applicationContext) {
		applicationContext.addBeanFactoryPostProcessor(new CachingMetadataReaderFactoryPostProcessor());
	}

ConfigurationWarningsApplicationContextInitializer:

java 复制代码
	@Override
	public void initialize(ConfigurableApplicationContext context) {
		context.addBeanFactoryPostProcessor(new ConfigurationWarningsPostProcessor(getChecks()));
	}

RSocketPortInfoApplicationContextInitializer:

java 复制代码
	@Override
	public void initialize(ConfigurableApplicationContext applicationContext) {
		applicationContext.addApplicationListener(new Listener(applicationContext));
	}

ServerPortInfoApplicationContextInitializer:

java 复制代码
	@Override
	public void initialize(ConfigurableApplicationContext applicationContext) {
		applicationContext.addApplicationListener(this);
	}

ConditionEvaluationReportLoggingListener:

java 复制代码
	@Override
	public void initialize(ConfigurableApplicationContext applicationContext) {
		this.applicationContext = applicationContext;
		applicationContext.addApplicationListener(new ConditionEvaluationReportListener());
		if (applicationContext instanceof GenericApplicationContext) {
			// Get the report early in case the context fails to load
			this.report = ConditionEvaluationReport.get(this.applicationContext.getBeanFactory());
		}
	}


七个ApplicationContextInitializer执行完毕之后,增加了两个bfpp,三个listeners。

listeners.contextPrepared(context);发布事件通知

EventPublishingRunListener类的contextPrepared方法,发布的是ApplicationContextInitializedEvent事件,会有对应的监听器执行

java 复制代码
	@Override
	public void contextPrepared(ConfigurableApplicationContext context) {
		this.initialMulticaster
				.multicastEvent(new ApplicationContextInitializedEvent(this.application, this.args, context));
	}

打印启动日志输出:

java 复制代码
logStarting:56, StartupInfoLogger (org.springframework.boot)
logStartupInfo:637, SpringApplication (org.springframework.boot)
prepareContext:373, SpringApplication (org.springframework.boot)
run:314, SpringApplication (org.springframework.boot)
run:1226, SpringApplication (org.springframework.boot)
run:1215, SpringApplication (org.springframework.boot)
main:18, SpringbootWebApplication (com.mashibing)
java 复制代码
	private CharSequence getStartingMessage() {
		StringBuilder message = new StringBuilder();
		message.append("Starting ");
		appendApplicationName(message);
		appendVersion(message, this.sourceClass);
		appendOn(message);
		appendPid(message);
		appendContext(message);
		return message;
	}

load(context, sources.toArray(new Object[0]));

load方法有自动装配的核心点

java 复制代码
load:151, BeanDefinitionLoader (org.springframework.boot)
load:136, BeanDefinitionLoader (org.springframework.boot)
load:128, BeanDefinitionLoader (org.springframework.boot)
load:691, SpringApplication (org.springframework.boot)
prepareContext:392, SpringApplication (org.springframework.boot)
run:314, SpringApplication (org.springframework.boot)
run:1226, SpringApplication (org.springframework.boot)
run:1215, SpringApplication (org.springframework.boot)
main:20, SpringbootWebApplication (com.mashibing)

匹配启动类上是否有@Component注解

java 复制代码
	private boolean isComponent(Class<?> type) {
		// This has to be a bit of a guess. The only way to be sure that this type is
		// eligible is to make a bean definition out of it and try to instantiate it.
		if (MergedAnnotations.from(type, SearchStrategy.TYPE_HIERARCHY).isPresent(Component.class)) {
			return true;
		}
		// Nested anonymous classes are not eligible for registration, nor are groovy
		// closures
		return !type.getName().matches(".*\\$_.*closure.*") && !type.isAnonymousClass()
				&& type.getConstructors() != null && type.getConstructors().length != 0;
	}

@SpringBootApplication注解的继承图如下:

然后开始下面的注册流程:

执行当前启动类:

当前springboot项目的启动类注册bean定义信息给beanfactory,后续交给spring管理生命周期,并且执行bfpp的自动装配扫描包等操作

至此,项目启动类注册bean定义信息成功。

load(context, sources.toArray(new Object[0]));执行结束之后,执行listeners.contextLoaded(context);方法

java 复制代码
addBeanFactoryPostProcessor:488, AbstractApplicationContext (org.springframework.context.support)
addPostProcessors:222, ConfigFileApplicationListener (org.springframework.boot.context.config)
onApplicationPreparedEvent:203, ConfigFileApplicationListener (org.springframework.boot.context.config)
onApplicationEvent:179, ConfigFileApplicationListener (org.springframework.boot.context.config)
doInvokeListener:172, SimpleApplicationEventMulticaster (org.springframework.context.event)
invokeListener:165, SimpleApplicationEventMulticaster (org.springframework.context.event)
multicastEvent:139, SimpleApplicationEventMulticaster (org.springframework.context.event)
multicastEvent:127, SimpleApplicationEventMulticaster (org.springframework.context.event)
contextLoaded:93, EventPublishingRunListener (org.springframework.boot.context.event)
contextLoaded:65, SpringApplicationRunListeners (org.springframework.boot)
prepareContext:393, SpringApplication (org.springframework.boot)
run:314, SpringApplication (org.springframework.boot)
run:1226, SpringApplication (org.springframework.boot)
run:1215, SpringApplication (org.springframework.boot)
main:20, SpringbootWebApplication (com.mashibing)

再添加一个BFPP现在加上上面添加的两个 现在有三个了。

打印结束日志

csharp 复制代码
2024-11-06 17:08:18.350  INFO 79556 --- [           main] com.mashibing.SpringbootWebApplication   : Started SpringbootWebApplication in 1768.089 seconds (JVM running for 1792.346)


13.刷新应用上下文 完成Spring容器的初始化

refreshContext(context);
Spring源码-ConfigurationClassPostProcessor类解析spring相关注解以及springboot自动装配原理(必会)

refreshContext这个方法实现了spring容器的创建,其中包含了容器内对象的实例化、初始化、属性填充。以及SpringBoot的自动装配原理,这个方法在之前的Spring源码中有详细解读,请移步Spring源码详解

这里还完成了SpringBoot内嵌Tomcat的初始化过程SpringBoot源码-SpringBoot内嵌Tomcat原理

14.刷新后操作

java 复制代码
afterRefresh(context, applicationArguments);
java 复制代码
	/**
	 * Called after the context has been refreshed.
	 * @param context the application context
	 * @param args the application arguments
	 */
	protected void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) {
	}

15.结束记录启动时间

stopWatch.stop();

java 复制代码
	/**
	 * Stop the current task.
	 * <p>The results are undefined if timing methods are called without invoking
	 * at least one pair of {@code start()} / {@code stop()} methods.
	 * @see #start()
	 * @see #start(String)
	 */
	public void stop() throws IllegalStateException {
		if (this.currentTaskName == null) {
			throw new IllegalStateException("Can't stop StopWatch: it's not running");
		}
		long lastTime = System.nanoTime() - this.startTimeNanos;
		this.totalTimeNanos += lastTime;
		this.lastTaskInfo = new TaskInfo(this.currentTaskName, lastTime);
		if (this.keepTaskList) {
			this.taskList.add(this.lastTaskInfo);
		}
		++this.taskCount;
		this.currentTaskName = null;
	}
相关推荐
JohnYan18 分钟前
工作笔记- 记一次MySQL数据移植表空间错误排除
数据库·后端·mysql
程序员清风41 分钟前
阿里二面:Kafka 消费者消费消息慢(10 多分钟),会对 Kafka 有什么影响?
java·后端·面试
幼稚园的山代王41 分钟前
Prompt Enginering(提示工程)先进技术
java·人工智能·ai·chatgpt·langchain·prompt
周某某~1 小时前
二.单例模式‌
java·单例模式·设计模式
摸鱼仙人~1 小时前
深入理解Java单例模式:确保类只有一个实例
java·javascript·单例模式
CodeSheep1 小时前
宇树科技,改名了!
前端·后端·程序员
hstar95271 小时前
三十五、面向对象底层逻辑-Spring MVC中AbstractXlsxStreamingView的设计
java·后端·spring·设计模式·架构·mvc
楽码1 小时前
AI决策树:整理繁杂问题的简单方法
人工智能·后端·openai
星辰大海的精灵1 小时前
基于Dify+MCP实现通过微信发送天气信息给好友
人工智能·后端·python
import_random1 小时前
[深度学习]5大神经网络架构(介绍)
后端