目录

  • 一、背景
    • 1.1、刷新的整体调用流程
    • 1.2、本文解读范围
  • 二、初始化特定上下文子类中的其他特殊bean
    • 2.1、初始化主体资源
    • 2.2、创建web服务
  • 三、检查监听器bean并注册它们
  • 四、实例化所有剩余的(非惰性初始化)单例
  • 五、发布相应的事件
    • 5.1、清除上下文级别的资源缓存
    • 5.2、初始化声明周期处理器
    • 5.3、将刷新传播到生命周期处理器
    • 5.4、发布事件
  • 结语

一、背景

  上一篇我们解读了刷新应用上下文(中),本篇主要解读刷新应用上下文(下),老样子还是回顾下刷新的整体流程,这样就能不迷路。

1.1、刷新的整体调用流程

  此方法所在类的具体路径:org.springframework.boot.SpringApplication

 private void refreshContext(ConfigurableApplicationContext context) {if (this.registerShutdownHook) {// 又增加一个监听器ApplicationContextClosedListener,上一文我们讲过准备刷新是11个,现在就是12个了shutdownHook.registerApplicationContext(context);}refresh(context);}protected void refresh(ConfigurableApplicationContext applicationContext) {// 最终实现是AbstractApplicationContext的refresh方法applicationContext.refresh();}

  此方法所在类的具体路径:org.springframework.context.support.AbstractApplicationContext

@Overridepublic void refresh() throws BeansException, IllegalStateException {// 同步的方式刷新synchronized (this.startupShutdownMonitor) {StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");// 准备此上下文以进行刷新prepareRefresh();// 告诉子类刷新内部bean工厂ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// 准备bean工厂,以便在此上下文中使用prepareBeanFactory(beanFactory);try {// 允许在上下文中子类对bean工厂进行后处理postProcessBeanFactory(beanFactory);StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");// 调用在上下文中注册为beanFactory的后置处理器invokeBeanFactoryPostProcessors(beanFactory);// 注册拦截bean创建的BeanPostProcessorregisterBeanPostProcessors(beanFactory);beanPostProcess.end();// 为此上下文初始化消息源,也就是注册DelegatingMessageSourceinitMessageSource();// 为此上下文初始化事件multicasterinitApplicationEventMulticaster();// 初始化特定上下文子类中的其他特殊bean,比如创建内置的Servlet容器onRefresh();// 检查监听器bean并注册它们registerListeners();// 实例化所有剩余的(非惰性初始化)单例finishBeanFactoryInitialization(beanFactory);// 最后一步:发布相应的事件finishRefresh();} catch (BeansException ex) {if (logger.isWarnEnabled()) {logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex);}// 销毁已创建的单例以避免悬空资源destroyBeans();// 重置“active”标志cancelRefresh(ex);// 将异常传播到调用方throw ex;} finally {//重置Spring核心中的常见内省缓存,因为我们可能不再需要单例bean的元数据了。。。resetCommonCaches();contextRefresh.end();}}}

1.2、本文解读范围

  本文主要讲解refresh()方法的部分内容,也就是:

 // 前面已讲解,就省略了try {// 前面已讲解,就省略了// 初始化特定上下文子类中的其他特殊bean,比如创建内置的Servlet容器onRefresh();// 检查监听器bean并注册它们registerListeners();// 实例化所有剩余的(非惰性初始化)单例finishBeanFactoryInitialization(beanFactory);// 最后一步:发布相应的事件finishRefresh();} catch (BeansException ex) {}finally{}

二、初始化特定上下文子类中的其他特殊bean

  此方法所在类的具体路径:org.springframework.context.support.AbstractApplicationContext

 @Overrideprotected void onRefresh() {super.onRefresh();try {createWebServer();}catch (Throwable ex) {throw new ApplicationContextException("Unable to start web server", ex);}}

2.1、初始化主体资源

  调用父类的onRefresh方法,实际是子类重新的方法,具体的实现是:org.springframework.web.context.support.GenericWebApplicationContext来完成的

public class GenericWebApplicationContext extends GenericApplicationContextimplements ConfigurableWebApplicationContext, ThemeSource {@Nullableprivate ThemeSource themeSource;@Overrideprotected void onRefresh() {// 初始化主体资源this.themeSource = UiApplicationContextUtils.initThemeSource(this);}
}

2.2、创建web服务

  这里我们主要看看createWebServer()方法,看看它做了什么。

 private void createWebServer() {// 获取webServer,此时为nullWebServer webServer = this.webServer;// 获取Servlet上下文,此时为nullServletContext servletContext = getServletContext();if (webServer == null && servletContext == null) {StartupStep createWebServer = this.getApplicationStartup().start("spring.boot.webserver.create");// 获取WebServer工厂为TomcatServletWebServerFactoryServletWebServerFactory factory = getWebServerFactory();createWebServer.tag("factory", factory.getClass().toString());// 获取Servlet上下文初始化器,结果是ServletWebServerApplicationContext// 通过工厂创建webServerthis.webServer = factory.getWebServer(getSelfInitializer());createWebServer.end();getBeanFactory().registerSingleton("webServerGracefulShutdown",new WebServerGracefulShutdownLifecycle(this.webServer));getBeanFactory().registerSingleton("webServerStartStop",new WebServerStartStopLifecycle(this, this.webServer));} else if (servletContext != null) {try {getSelfInitializer().onStartup(servletContext);} catch (ServletException ex) {throw new ApplicationContextException("Cannot initialize servlet context", ex);}}initPropertySources();}

  调用createWebServer方法去创建内置的Servlet容器,目前SpringBoot只支持3种内置的Servlet容器:

  • Tomcat
  • Jetty
  • Undertow

  因为我这边的依赖是:

    <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><version>2.6.0</version></dependency>

  所以这边默认是使用Tomcat容器

 protected ServletWebServerFactory getWebServerFactory() {// Use bean names so that we don't consider the hierarchy// getBeanFactory或到的是DefaultListableBeanFactory// 此处获取到的beanNames是tomcatServletWebServerFactoryString[] beanNames = getBeanFactory().getBeanNamesForType(ServletWebServerFactory.class);if (beanNames.length == 0) {throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to missing "+ "ServletWebServerFactory bean.");}if (beanNames.length > 1) {throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to multiple "+ "ServletWebServerFactory beans : " + StringUtils.arrayToCommaDelimitedString(beanNames));}// 返回TomcatServletWebServerFactoryreturn getBeanFactory().getBean(beanNames[0], ServletWebServerFactory.class);}

三、检查监听器bean并注册它们

  此方法所在类的具体路径:org.springframework.context.support.AbstractApplicationContext

 protected void registerListeners() {// 首先注册指定的静态侦听器。for (ApplicationListener<?> listener : getApplicationListeners()) {getApplicationEventMulticaster().addApplicationListener(listener);}// 不要在这里初始化FactoryBeans:我们需要保留所有常规Bean未被初始化,为了让后处理器对它们处理String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);for (String listenerBeanName : listenerBeanNames) {getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);}// 发布早期应用程序事件Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;this.earlyApplicationEvents = null;if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {for (ApplicationEvent earlyEvent : earlyEventsToProcess) {getApplicationEventMulticaster().multicastEvent(earlyEvent);}}}

  getApplicationListeners()方法获取的监听器有13个,原本通过Spring工厂加载的结果是8个(参考:Alian解读SpringBoot 2.6.0 源码(一):SpringApplication对象创建(Spring工厂加载机制)),准备应用上下文之前的方法applyInitializers加载了3个监听器(参考:Alian解读SpringBoot 2.6.0 源码(七):启动流程分析之准备应用上下文),刷新应用上下文时添加了2个(参考:Alian解读SpringBoot 2.6.0 源码(八):启动流程分析之刷新应用上下文(上))最终应用上下文里的监听器如下:

  • RSocketPortInfoApplicationContextInitializer的静态内部类Listener(准备应用上下文添加的)
  • ServerPortInfoApplicationContextInitializer(准备应用上下文添加的)
  • ConditionEvaluationReportLoggingListener的静态内部类ConditionEvaluationReportListener(准备应用上下文添加的)
  • EnvironmentPostProcessorApplicationListener(应用上下文加载事件添加的)
  • AnsiOutputApplicationListener(应用上下文加载事件添加的)
  • LoggingApplicationListener(应用上下文加载事件添加的)
  • BackgroundPreinitializer(应用上下文加载事件添加的)
  • DelegatingApplicationListener(应用上下文加载事件添加的)
  • ParentContextCloserApplicationListener(应用上下文加载事件添加的)
  • ClearCachesApplicationListener(应用上下文加载事件添加的)
  • FileEncodingApplicationListener(应用上下文加载事件添加的)
  • ApplicationContextClosedListener(刷新应用上下文refreshContext添加的)
  • SharedMetadataReaderFactoryBean(刷新应用上下文refreshContext添加的)

获取到的监听器的名称有:

  • &org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory
  • mvcResourceUrlProvider
  • springApplicationAdminRegistrar
  • applicationAvailability

此时earlyApplicationEvents为空,故没有早期事件需要发布

四、实例化所有剩余的(非惰性初始化)单例

  此方法所在类的具体路径:org.springframework.context.support.AbstractApplicationContext

 protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {// 为此上下文初始化转换服务。if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {beanFactory.setConversionService(beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));}// 判断是否有嵌入值解析器if (!beanFactory.hasEmbeddedValueResolver()) {// 没有就注册一个beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));}// 尽早初始化LoadTimeWeaverAware bean,以便尽早注册其转换器。String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);for (String weaverAwareName : weaverAwareNames) {getBean(weaverAwareName);}// 停止使用临时类加载器进行类型匹配beanFactory.setTempClassLoader(null);// 允许缓存所有bean定义元数据,不需要进一步更改。beanFactory.freezeConfiguration();// 实例化所有剩余的(非惰性初始化)单例。beanFactory.preInstantiateSingletons();}

  此方法所在类的具体路径:org.springframework.beans.factory.support.DefaultListableBeanFactory

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactoryimplements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {// 按注册顺序的bean定义名称的List列表private volatile List<String> beanDefinitionNames = new ArrayList<>(256);@Overridepublic void preInstantiateSingletons() throws BeansException {if (logger.isTraceEnabled()) {logger.trace("Pre-instantiating singletons in " + this);}// 创建一个迭代副本List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);// 触发所有非惰性单例bean的初始化for (String beanName : beanNames) {// 如果指定的bean对应于子bean定义,则遍历父bean定义,返回合并的RootBeanDefinitionRootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);// 不是抽象,是单例,并且不是懒加载的RootBeanDefinitionif (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {if (isFactoryBean(beanName)) {// 如果是工厂bean,加上工厂bean的前"&",并获取beanObject bean = getBean(FACTORY_BEAN_PREFIX + beanName);// 如果获取的bean是FactoryBean的实例if (bean instanceof FactoryBean) {// 转为FactoryBean<?>FactoryBean<?> factory = (FactoryBean<?>) bean;// 定义变量标识是否是饿汉式加载boolean isEagerInit;if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,getAccessControlContext());} else {isEagerInit = (factory instanceof SmartFactoryBean &&((SmartFactoryBean<?>) factory).isEagerInit());}if (isEagerInit) {// 饿汉式加载,通过beanName获取beangetBean(beanName);}}} else {// 非工厂bean,通过beanName获取beangetBean(beanName);}}}// 触发所有适用bean的初始化后回调for (String beanName : beanNames) {Object singletonInstance = getSingleton(beanName);if (singletonInstance instanceof SmartInitializingSingleton) {StartupStep smartInitialize = this.getApplicationStartup().start("spring.beans.smart-initialize").tag("beanName", beanName);SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;if (System.getSecurityManager() != null) {AccessController.doPrivileged((PrivilegedAction<Object>) () -> {smartSingleton.afterSingletonsInstantiated();return null;}, getAccessControlContext());}else {smartSingleton.afterSingletonsInstantiated();}smartInitialize.end();}}}
}

  实例化BeanFactory中已经被注册但是未实例化的所有实例懒加载的不需要实例化,关于AbstractBeanFactory的getBean方法是非常核心的,内容也会比较多,我后面也会分单节去解读。

五、发布相应的事件

  此方法所在类的具体路径:org.springframework.context.support.AbstractApplicationContext

 protected void finishRefresh() {// 清除上下文级别的资源缓存(例如来自扫描的ASM元数据)clearResourceCaches();// 为此上下文初始化声明周期处理器initLifecycleProcessor();// 将刷新传播到生命周期处理器getLifecycleProcessor().onRefresh();// 发布事件publishEvent(new ContextRefreshedEvent(this));// 如果处于活动状态,请参与LiveBeansView MBean。if (!NativeDetector.inNativeImage()) {LiveBeansView.registerApplicationContext(this);}}

5.1、清除上下文级别的资源缓存

 public void clearResourceCaches() {// 这里主要是你编写的资源this.resourceCaches.clear();}

5.2、初始化声明周期处理器

 public static final String LIFECYCLE_PROCESSOR_BEAN_NAME = "lifecycleProcessor";protected void initLifecycleProcessor() {// 获取到的beanFactory是DefaultListableBeanFactoryConfigurableListableBeanFactory beanFactory = getBeanFactory();// 判断本地工厂是否含有beanName为lifecycleProcessor的beanif (beanFactory.containsLocalBean(LIFECYCLE_PROCESSOR_BEAN_NAME)) {// 包含则直接从beanFactory中获取this.lifecycleProcessor = beanFactory.getBean(LIFECYCLE_PROCESSOR_BEAN_NAME, LifecycleProcessor.class);if (logger.isTraceEnabled()) {logger.trace("Using LifecycleProcessor [" + this.lifecycleProcessor + "]");}} else {// 如果不包含,则初始化一个生命周期处理器DefaultLifecycleProcessor defaultProcessor = new DefaultLifecycleProcessor();defaultProcessor.setBeanFactory(beanFactory);this.lifecycleProcessor = defaultProcessor;// 注册到beanFactorybeanFactory.registerSingleton(LIFECYCLE_PROCESSOR_BEAN_NAME, this.lifecycleProcessor);if (logger.isTraceEnabled()) {logger.trace("No '" + LIFECYCLE_PROCESSOR_BEAN_NAME + "' bean, using " +"[" + this.lifecycleProcessor.getClass().getSimpleName() + "]");}}}

  beanName为lifecycleProcessor的bean是通过上面的方法beanFactory.preInstantiateSingletons()一系列操作后创建的,所以此处本地beanFactory就包含了它,也就是DefaultLifecycleProcessor

5.3、将刷新传播到生命周期处理器

  此方法所在类的具体路径:org.springframework.context.support.DefaultLifecycleProcessor

public class DefaultLifecycleProcessor implements LifecycleProcessor, BeanFactoryAware {@Overridepublic void onRefresh() {startBeans(true);this.running = true;}private void startBeans(boolean autoStartupOnly) {// 获取生命周期的beanMap<String, Lifecycle> lifecycleBeans = getLifecycleBeans();Map<Integer, LifecycleGroup> phases = new TreeMap<>();// 遍历lifecycleBeans,此处autoStartupOnly默认为truelifecycleBeans.forEach((beanName, bean) -> {// 如果是SmartLifecycle 的实例,并且是自动启动if (!autoStartupOnly || (bean instanceof SmartLifecycle && ((SmartLifecycle) bean).isAutoStartup())) {// 获取phaseint phase = getPhase(bean);// 如果phases中phase对应的value不存在,重新构建LifecycleGroup放入phasesphases.computeIfAbsent(phase,p -> new LifecycleGroup(phase, this.timeoutPerShutdownPhase, lifecycleBeans, autoStartupOnly)).add(beanName, bean);}});if (!phases.isEmpty()) {// phases 不为空,则进行遍历,并调用对应的LifecycleGroup的start方法phases.values().forEach(LifecycleGroup::start);}}protected Map<String, Lifecycle> getLifecycleBeans() {// 获取到的beanFactory是DefaultListableBeanFactoryConfigurableListableBeanFactory beanFactory = getBeanFactory();Map<String, Lifecycle> beans = new LinkedHashMap<>();// 通过beanFactory获取Lifecycle类型的名称列表,不包含单例,不允许饿汉式加载// 此处得到3个:lifecycleProcessor、webServerGracefulShutdown、webServerStartStopString[] beanNames = beanFactory.getBeanNamesForType(Lifecycle.class, false, false);// 遍历名称列表for (String beanName : beanNames) {// 返回实际的bean名称String beanNameToRegister = BeanFactoryUtils.transformedBeanName(beanName);// 判断是否是一个工厂bean,此处是falseboolean isFactoryBean = beanFactory.isFactoryBean(beanNameToRegister);// 如果是工厂bean,则加一个"&"String beanNameToCheck = (isFactoryBean ? BeanFactory.FACTORY_BEAN_PREFIX + beanName : beanName);// beanFactory包含此单例bean// 不是工厂bean 或者 是Lifecycle的实例  或者 是SmartLifecycle的实例if ((beanFactory.containsSingleton(beanNameToRegister) &&(!isFactoryBean || matchesBeanType(Lifecycle.class, beanNameToCheck, beanFactory))) ||matchesBeanType(SmartLifecycle.class, beanNameToCheck, beanFactory)) {Object bean = beanFactory.getBean(beanNameToCheck);if (bean != this && bean instanceof Lifecycle) {beans.put(beanNameToRegister, (Lifecycle) bean);}}}// 最终的结果:// "webServerGracefulShutdown" -> WebServerGracefulShutdownLifecycle// "webServerStartStop" -> WebServerStartStopLifecyclereturn beans;}
}

  首先会去获取生命周期bean,然后进行过滤(得是SmartLifecycle 的实例),然后执行生命周期bean的start方法,此处的结果是:

  • WebServerGracefulShutdownLifecycle
  • WebServerStartStopLifecycle

  而WebServerStartStopLifecycle会通过SimpleApplicationEventMulticaster发布ServletWebServerInitializedEvent事件,此事件获取的监听器有3个:

监听器 功能
SpringApplicationAdminMXBeanRegistrar 设置embeddedWebApplication为true
DelegatingApplicationListener 什么都没有做
ServerPortInfoApplicationContextInitializer 给名称为server.ports的MapPropertySource设置local.server.port的端口值,如9000

5.4、发布事件

  此方法所在类的具体路径:org.springframework.context.support.AbstractApplicationContext

 @Overridepublic void publishEvent(ApplicationEvent event) {publishEvent(event, null);}protected void publishEvent(Object event, @Nullable ResolvableType eventType) {Assert.notNull(event, "Event must not be null");ApplicationEvent applicationEvent;// 判断event是否是ApplicationEvent的实例if (event instanceof ApplicationEvent) {// 是,转为ApplicationEventapplicationEvent = (ApplicationEvent) event;} else {// 不是,通过PayloadApplicationEvent来装饰为applicationEventapplicationEvent = new PayloadApplicationEvent<>(this, event);if (eventType == null) {eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();}}// 此时earlyApplicationEvents 为nullif (this.earlyApplicationEvents != null) {// 早期事件不为nullthis.earlyApplicationEvents.add(applicationEvent);} else {// 不为null,则广播事件getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);}// 父上下文不为空if (this.parent != null) {// 父上下文是AbstractApplicationContext的实例if (this.parent instanceof AbstractApplicationContext) {// 转为AbstractApplicationContext,然后发布事件((AbstractApplicationContext) this.parent).publishEvent(event, eventType);} else {// 直接使用父上下文发布事件this.parent.publishEvent(event);}}}

  广播事件的流程讲过很多次了,就不多说了,通过SimpleApplicationEventMulticaster发布ContextRefreshedEvent事件,最终获取的监听器有5个:

  • DelegatingApplicationListener
  • ConditionEvaluationReportListener(ConditionEvaluationReportLoggingListener 的内部类)
  • ClearCachesApplicationListener
  • SharedMetadataReaderFactoryBean(SharedMetadataReaderFactoryContextInitializer 的内部类)
  • ResourceUrlProvider
监听器 功能
DelegatingApplicationListener 什么都不做
ConditionEvaluationReportListener 日志自动配置报告
ClearCachesApplicationListener 清除反射的缓存,清除类加载器的缓存
SharedMetadataReaderFactoryBean 清除元数据读取器工厂的并发引用缓存
ResourceUrlProvider 先清除资源请求处理器的缓存,然后把路径对应的资源请求处理重新放入,比如/webjars/** 对应的(META-INF/resources/webjars/)和 /** 对应的(classpath[META-INF/resources/,resources/,static/,public/],ServletContext [/])

结语

  其实到这里通过三篇应用上下文的刷新的解读,流程基本都清楚了,但是我们在后两篇文章中有说过,关于后置处理器的调用做了什么,以及本文中的getBean方法的执行做了什么,我们没有讲解,后面我们也会分析后置处理器的调用,以及getBean方法的执行了,期待您的关注。

Alian解读SpringBoot 2.6.0 源码(八):启动流程分析之刷新应用上下文(下)相关推荐

  1. Alian解读SpringBoot 2.6.0 源码(八):启动流程分析之刷新应用上下文(中)

    目录 一.背景 1.1.刷新的整体调用流程 1.2.本文解读范围 二.调用后处理器 2.1.调用在上下文中注册为beanFactory的后置处理器 2.2.invokeBeanFactoryPostP ...

  2. Alian解读SpringBoot 2.6.0 源码(七):启动流程分析之准备应用上下文

    目录 一.背景 1.1.run方法整体流程 1.2.本文解读范围 二.准备应用上下文 2.1.整体流程 2.2.设置环境 2.3.应用上下文进行后置处理 2.4.应用所有初始化器 2.5.发布应用上下 ...

  3. Alian解读SpringBoot 2.6.0 源码(十):启动流程之自动装配原理

    目录 一.背景 1.1.主类的加载 1.2.后置处理器的获取 二.配置类后处理器 2.1.获取配置类 2.2. 2.3.解析主类 2.3.1.整体解析过程 2.3.2.核心解析过程 2.3.3.延迟导 ...

  4. Alian解读SpringBoot 2.6.0 源码(六):启动流程分析之创建应用上下文

    目录 一.背景 1.1.run方法整体流程 1.2.本文解读范围 二.创建应用上下文 2.1.初始化入口 2.2.初始化AbstractApplicationContext 2.3.初始化Generi ...

  5. Alian解读SpringBoot 2.6.0 源码(九):启动流程分析之应用上下文刷新后处理(启动完成事件,Runner运行器,就绪事件)

    目录 一.背景 1.1.run方法整体流程 1.2.本文解读范围 二.应用上下文刷新后置处理 三.时间信息.输出日志记录执行主类名 四.发布应用上下文启动完成事件 4.1.ApplicationSta ...

  6. Alian解读SpringBoot 2.6.0 源码(二):启动流程分析之监听器解析

    目录 一.背景 1.1.run方法整体流程 1.2.本文解读范围 二.记录应用启动的开始时间 三.初始化启动上下文 3.1.初始化启动上下文 3.2.初始化应用程序事件广播器 3.3.初始化应用上下文 ...

  7. Alian解读SpringBoot 2.6.0 源码(八):启动流程分析之刷新应用上下文(上)

    目录 一.背景 1.1.run方法整体流程 1.2.刷新的整体调用流程 1.3.本文解读范围 二.准备刷新 2.1.准备刷新的流程 2.2.初始化上下文环境中servlet相关属性源 2.3.校验re ...

  8. Alian解读SpringBoot 2.6.0 源码(四):启动流程分析之应用环境准备

    目录 一.背景 1.1.run方法整体流程 1.2.本文解读范围 二.应用环境准备 2.1.准备环境的整体流程 2.2.创建环境 2.3.配置环境 2.3.1.注册默认的转换器.格式化组件 2.3.1 ...

  9. Alian解读SpringBoot 2.6.0 源码(一):SpringApplication对象创建(Spring工厂加载机制)

    目录 一.背景 二.SpringApplication实例化 2.1.实例化方法入口 2.2.推断应用程序类型 2.3.Spring工厂加载机制 2.3.1.获取Spring工厂实例(重要) 2.3. ...

最新文章

  1. mysql分组和where条件查询_【MySQL】:分组查询where和having
  2. 搞定一个C++项目最快需要多久?
  3. 字符串-验证回文串(双指针法)
  4. linux centos 安装配置tftp服务器
  5. 2018 焦作站亚洲区域赛校内选拔赛题解
  6. 智联招聘python岗位_Python爬虫爬取智联招聘职位信息
  7. AWS 用户指南笔记
  8. 程序员三年的门槛该如何跨过去?
  9. JavaIO15FileReader和FileWriter源码分析及介绍使用
  10. python 编写一个银行卡类,具有账号,人名与余额属性。编写提款机类,接收一张银行卡,并且具有存款,提款,查询余额,转账功能
  11. RS232,RS485简介,以及DB9接口上引脚对应关系
  12. C编程实例-“约瑟夫问题” 解法
  13. EXCEL复合条饼图制作
  14. 心田花开:小学三年级语文下册古诗词整理【全】
  15. Plustoken重要操盘手已被遣返回国,警方正全力侦查
  16. 无线安全渗透测试套件WiFi-Pumpkin新版本发布
  17. 【译】Linux不同的IO访问方式中,Scylla的选择和依据
  18. 图片报道:2008年12月4日夜,暴风雪突袭烟台(上)
  19. 什么是好的录屏软件?5 款值得收藏的屏幕录制软件
  20. SpringMVC个人理解(downpour 的SpringMVC深度探险的个人整理)

热门文章

  1. W + E load segments are not allowed
  2. Docker 基础常用命令
  3. 30多个小程序一键发布——miniprogram-ci
  4. 阿里云产品 ECS、RDS、CDN、OCS、OSS、ACE、SLB介绍
  5. 你应该知道的云计算行业最专业的教材
  6. 怎样批量自动上传图片
  7. java 文本框只读_css控制文本框的只读属性的方法
  8. ExtJs之事件绑定
  9. couchdb android,CouchDB on android 入门
  10. oracle查看rman进度,监控数据备份恢复完成进度(EXPDP/IMPDP/RMAN)