12.刷新前操作
// 刷新前操作prepareContext(context, environment, listeners, applicationArguments, printedBanner);
进入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 beansConfigurableListableBeanFactory 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 sourcesSet<Object> sources = getAllSources();Assert.notEmpty(sources, "Sources must not be empty");load(context, sources.toArray(new Object[0]));listeners.contextLoaded(context);}
***applyInitializers(context);实现细节如下***:
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方法。
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:
@Overridepublic void initialize(ConfigurableApplicationContext applicationContext) {applicationContext.addBeanFactoryPostProcessor(new CachingMetadataReaderFactoryPostProcessor());}
ConfigurationWarningsApplicationContextInitializer:
@Overridepublic void initialize(ConfigurableApplicationContext context) {context.addBeanFactoryPostProcessor(new ConfigurationWarningsPostProcessor(getChecks()));}
RSocketPortInfoApplicationContextInitializer:
@Overridepublic void initialize(ConfigurableApplicationContext applicationContext) {applicationContext.addApplicationListener(new Listener(applicationContext));}
ServerPortInfoApplicationContextInitializer:
@Overridepublic void initialize(ConfigurableApplicationContext applicationContext) {applicationContext.addApplicationListener(this);}
ConditionEvaluationReportLoggingListener:
@Overridepublic 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 loadthis.report = ConditionEvaluationReport.get(this.applicationContext.getBeanFactory());}}
七个ApplicationContextInitializer执行完毕之后,增加了两个bfpp,三个listeners。
listeners.contextPrepared(context);发布事件通知
EventPublishingRunListener类的contextPrepared方法,发布的是ApplicationContextInitializedEvent事件,会有对应的监听器执行
@Overridepublic void contextPrepared(ConfigurableApplicationContext context) {this.initialMulticaster.multicastEvent(new ApplicationContextInitializedEvent(this.application, this.args, context));}
打印启动日志输出:
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)
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方法有自动装配的核心点
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注解
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// closuresreturn !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);方法
:
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现在加上上面添加的两个 现在有三个了。
打印结束日志
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.刷新后操作
afterRefresh(context, applicationArguments);
/*** 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();
/*** 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;}