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;
	}
相关推荐
~kiss~1 分钟前
Rust~二刷异步逻辑
开发语言·后端·rust
菠菠萝宝4 分钟前
【Java八股文】11-分布式及场景面试篇
java·分布式·面试·k8s·系统·uuid·mq
SomeB1oody9 分钟前
【Rust中级教程】2.7. API设计原则之灵活性(flexible) Pt.3:借用 vs. 拥有、`Cow`类型、可失败和阻塞的析构函数及解决办法
开发语言·后端·性能优化·rust
LUCIAZZZ11 分钟前
Https解决了Http的哪些问题
java·网络·网络协议·spring·http·rpc·https
larance18 分钟前
Flask 发送邮件
后端·python·flask
Aska_Lv24 分钟前
从零到一写组件库-日志组件库
后端
论迹32 分钟前
【JavaEE】-- 多线程(初阶)2
java·开发语言·java-ee
桃子是唯一的水果41 分钟前
java 单例模式(Lazy Initialization)实现遍历文件夹下所有excel文件且返回其运行时间
java·单例模式·maven
+72043 分钟前
如何在java中用httpclient实现rpc post 请求
java·开发语言·rpc
ybq1951334543144 分钟前
javaEE-SpringBoot日志
java·spring boot·后端