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

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 Object0));执行结束之后,执行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;
	}
相关推荐
M-Robots echo4 小时前
轻量化裁剪方案解析:M-Robots 模块化构建,适配高低端各类机器人硬件平台
java·机器人·ros·开源社区·atomgit·m-robots
笃行3504 小时前
SQLServer数据迁移之后,那张报表还能不能秒出
后端
不可求~4 小时前
多模型路由怎么落地:把任务分流写进项目的最小实现
java·前端·数据库
LucianaiB5 小时前
别再被 AI 骗了:我把腾讯云 4 个 Skill 做成了个「AI 打假侦探」,过程的一个小配置坑惨了我
后端
mldong5 小时前
用 DDD 设计工作流引擎:聚合根与充血模型
java·架构
candyTong5 小时前
Claude Code 如何恢复一段会话
后端·架构·ai编程
mqiqe6 小时前
AgentScope Java Harness:4. 双层记忆系统 让 Agent 拥有真正的“长期大脑“
java·开发语言
伍一516 小时前
03-文件管理模块-一个看似简单的模块藏着多少细节
java·ruoyi·若依
gugucoding6 小时前
46. 【Java】JUC并发工具:让并发更简单
java·开发语言
En^_^Joy6 小时前
Django项目配置全攻略:settings配置文件
后端·python·django