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

目录

    • 一、背景
      • 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

@Override
	public 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创建的BeanPostProcessor
				registerBeanPostProcessors(beanFactory);
				beanPostProcess.end();

				// 为此上下文初始化消息源,也就是注册DelegatingMessageSource
				initMessageSource();

				// 为此上下文初始化事件multicaster
				initApplicationEventMulticaster();

				// 初始化特定上下文子类中的其他特殊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

	@Override
	protected 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 GenericApplicationContext
		implements ConfigurableWebApplicationContext, ThemeSource {

	@Nullable
	private ThemeSource themeSource;
	@Override
	protected void onRefresh() {
		// 初始化主体资源
		this.themeSource = UiApplicationContextUtils.initThemeSource(this);
	}
}

2.2、创建web服务

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

	private void createWebServer() {
		// 获取webServer,此时为null
		WebServer webServer = this.webServer;
		// 获取Servlet上下文,此时为null
		ServletContext servletContext = getServletContext();
		if (webServer == null && servletContext == null) {
			StartupStep createWebServer = this.getApplicationStartup().start("spring.boot.webserver.create");
			// 获取WebServer工厂为TomcatServletWebServerFactory
			ServletWebServerFactory factory = getWebServerFactory();
			createWebServer.tag("factory", factory.getClass().toString());
			// 获取Servlet上下文初始化器,结果是ServletWebServerApplicationContext
			// 通过工厂创建webServer
			this.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.bootgroupId>
        <artifactId>spring-boot-starter-webartifactId>
        <version>2.6.0version>
    dependency>

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

	protected ServletWebServerFactory getWebServerFactory() {
		// Use bean names so that we don't consider the hierarchy
		// getBeanFactory或到的是DefaultListableBeanFactory
		// 此处获取到的beanNames是tomcatServletWebServerFactory
		String[] 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));
		}
		// 返回TomcatServletWebServerFactory
		return 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 AbstractAutowireCapableBeanFactory
		implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
	// 按注册顺序的bean定义名称的List列表
	private volatile List<String> beanDefinitionNames = new ArrayList<>(256);
	
	@Override
	public 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定义,返回合并的RootBeanDefinition
			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
			// 不是抽象,是单例,并且不是懒加载的RootBeanDefinition 
			if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
				if (isFactoryBean(beanName)) {
					// 如果是工厂bean,加上工厂bean的前"&",并获取bean
					Object 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获取bean
							getBean(beanName);
						}
					}
				} else {
					// 非工厂bean,通过beanName获取bean
					getBean(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中已经被注册但是未实例化的所有实例懒加载的不需要实例化,关于AbstractBeanFactorygetBean方法是非常核心的,内容也会比较多,我后面也会分单节去解读。

五、发布相应的事件

  此方法所在类的具体路径: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是DefaultListableBeanFactory
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
		// 判断本地工厂是否含有beanName为lifecycleProcessor的bean
		if (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;
			// 注册到beanFactory
			beanFactory.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 {
	@Override
	public void onRefresh() {
		startBeans(true);
		this.running = true;
	}

	private void startBeans(boolean autoStartupOnly) {
		// 获取生命周期的bean
		Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
		Map<Integer, LifecycleGroup> phases = new TreeMap<>();
		// 遍历lifecycleBeans,此处autoStartupOnly默认为true
		lifecycleBeans.forEach((beanName, bean) -> {
			// 如果是SmartLifecycle 的实例,并且是自动启动
			if (!autoStartupOnly || (bean instanceof SmartLifecycle && ((SmartLifecycle) bean).isAutoStartup())) {
				// 获取phase 
				int phase = getPhase(bean);
				// 如果phases中phase对应的value不存在,重新构建LifecycleGroup放入phases 
				phases.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是DefaultListableBeanFactory
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
		Map<String, Lifecycle> beans = new LinkedHashMap<>();
		// 通过beanFactory获取Lifecycle类型的名称列表,不包含单例,不允许饿汉式加载
		// 此处得到3个:lifecycleProcessor、webServerGracefulShutdown、webServerStartStop
		String[] beanNames = beanFactory.getBeanNamesForType(Lifecycle.class, false, false);
		// 遍历名称列表
		for (String beanName : beanNames) {
			// 返回实际的bean名称
			String beanNameToRegister = BeanFactoryUtils.transformedBeanName(beanName);
			// 判断是否是一个工厂bean,此处是false
			boolean 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" -> WebServerStartStopLifecycle
		return beans;
	}
}

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

  • WebServerGracefulShutdownLifecycle
  • WebServerStartStopLifecycle

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

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

5.4、发布事件

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

	@Override
	public 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) {
			// 是,转为ApplicationEvent
			applicationEvent = (ApplicationEvent) event;
		} else {
			// 不是,通过PayloadApplicationEvent来装饰为applicationEvent 
			applicationEvent = new PayloadApplicationEvent<>(this, event);
			if (eventType == null) {
				eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
			}
		}
		// 此时earlyApplicationEvents 为null
		if (this.earlyApplicationEvents != null) {
			// 早期事件不为null
			this.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方法的执行了,期待您的关注。

你可能感兴趣的:(Spring,Boot,源码,SpringBoot源码,SpringBoot2.6.0,refresh)