SpringBoot启动流程
2021-03-29 09:59:50 3 举报
SpringBoot启动流程&Spring 容器刷新
作者其他创作
大纲/内容
return context
supportsSourceType(sourceType)
执行刷新容器后的后置处理逻辑,注意这里为空方法,留给扩展使用
注册没实现优先级接口的BeanPostProcessor
onRefresh()
创建一个tomcat,配置tomcat的基本环境new Tomcat()
所有Bean都利用getBean创建完成以后;检查所有的Bean是否是SmartInitializingSingleton接口实现类的;如果是-就执行afterSingletonsInstantiated();
this.fallbackBanner
beanFactory instanceof BeanDefinitionRegistry
返回GenericApplicationContext无参构造函数内-创建的BeanFactory--DefaultListableBeanFactory对象
在Bean创建完成后检查是否是ApplicationListener,如果是\t\t\tapplicationContext.addApplicationListener((ApplicationListener<?>) bean)
finishRefresh()
调用到函数org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#selfInitialize(),在这个方法中会从Spring容器中获取所有ServletContextInitializer,并调用其onStartup 方法,当调用DispatcherServletRegistryBean的onStartup方法时,就将DispatcherServlet添加的Servlet容器中了。而DispatcherServletRegistryBean是通过DispatcherServletAutoConfiguration这个配置类自动注入到Spring容器中的,从而完成了自动装配
setInitializers(getSpringFactoriesInstances( ApplicationContextInitializer.class))
listener.onApplicationEvent(event);
遍历
catch
开始
循环处理配置类configClass直到sourceClass变为nulldoProcessConfigurationClass的返回值是其参数configClass的父类,如果该父类是由Java提供的类或者已经处理过,返回null
1、对加了@Configuration注解的类进行CGLIB代理,注意此时由于完成SpringBoot的自动配置,此时@Configuration注解类可不是只有一个启动类了,一大堆自动配置类2、向Spring中添加一个后置处理器ImportAwareBeanPostProcessor
setListeners(getSpringFactoriesInstances(ApplicationListener.class))
内部创建TomcatStarter实例,并通过构造函数传入ServletContextInitializer
deferredImports.forEach(handler::register);
依据不同环境创建不同的容器对象1、servlet环境:AnnotationConfigServletWebServerApplicationContext2、reactive环境:AnnotationConfigReactiveWebServerApplicationContext3、default:AnnotationConfigApplicationContext
是
获取当前Bean注册中心当前注册全部Bean,有5个Bean是创建ApplicationContext注册的,SpringBoot启动类和CachingMetadataReaderFactoryPostProcessor实在prepareContext()方法注册到容器当中
1)第一阶段处理BeanDefinitionRegistryPostProcessors.class 判断当前beanFactory是否是BeanDefinitionRegistry 1)是,当前是DefaultListableBeanFactory所以走此处逻辑 1、遍历形参beanFactoryPostProcessors,判断当前BeanFactoryPostProcessor是否是子接口BeanDefinitionRegistryPostProcessor 如果是,则执行postProcessBeanDefinitionRegistry方法 并registryProcessors.add(registryProcessor)便于后续执行父接口方法; 如果不是,则为父接口实例,暂存起来后面统一执行postProcessBeanFactory,regularPostProcessors.add(postProcessor); 2、获取beanFactory注册的所有类型为BeanDefinitionRegistryPostProcessor.class的bean 1)、先执行(先排序再执行)实现了PriorityOrdered优先级接口的BeanDefinitionRegistryPostProcessor、 postProcessor.postProcessBeanDefinitionRegistry(registry)--执行了ConfigurationClassPostProcessor registryProcessors.addAll(currentRegistryProcessors)便于后续执行父接口方法; 2)、再执行(先排序再执行)实现了Ordered顺序接口的BeanDefinitionRegistryPostProcessor; postProcessor.postProcessBeanDefinitionRegistry(registry) registryProcessors.addAll(currentRegistryProcessors)便于后续执行父接口方法; 3)、最后执行(先排序再执行)没有实现任何优先级或者是顺序接口的BeanDefinitionRegistryPostProcessors; postProcessor.postProcessBeanDefinitionRegistry(registry) registryProcessors.addAll(currentRegistryProcessors)便于后续执行父接口方法; 3、执行形参beanFactoryPostProcessors中BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessors(来自形参中BeanDefinitionRegistryPostProcessor+来自BeanFactory中BeanDefinitionRegistryPostProcessor)中的postProcessBeanFactory()方法 //registryProcessors存放的是BeanDefinitionRegistryPostProcessor font color=\"#ff6666\
步骤三
return banners
invokeBeanFactoryPostProcessors(beanFactory)
默认返回
给容器中注册internalBeanProcessor
GenericApplicationContext.class@Override public final ConfigurableListableBeanFactory getBeanFactory() { return this.beanFactory; }
读取当前classpath下当前包,以及所有依赖包META-INF/spring.factories
resetCommonCaches()
否
先获取ioc容器已经定义了的需要创建对象的所有BeanPostProcessor这里测试发现,自定义的BeanProcessor也在此处获取
调用各个ApplicationContextInitializer-initialize方法
是否是工厂bean
加载接口实现类-SpringFactoriesLoader.loadFactoryNames()
listeners.started(context)
for (String beanName : beanNames){}
创建BeanName生成器
context.addBeanFactoryPostProcessor( new PropertySourceOrderingPostProcessor(context))
allListeners.add(listener);整体执行逻辑从spring.factories中加载的全部ApplicationListener筛选出订阅此事件的全部AppLicationListener
finishBeanFactoryInitialization(beanFactory)
加载Bean
每个定制器的方法-customize(ConfigurableServletWebServerFactory factory),为TomcatServletWebServerFactory相关属性赋值
1、按照顺序执行ApplicationContext与BeanFactory注册的BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor实现类对应的方法2、SpringBoot的AutoConfiguration自动装配发生在此步骤
finally
执行形参beanFactoryPostProcessors中BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessors(来自形参中BeanDefinitionRegistryPostProcessor+来自BeanFactory中BeanDefinitionRegistryPostProcessor)中的postProcessBeanFactory()方法
new ClassPathBeanDefinitionScanner(this);
默认执行
返回TomcatServletWebServerFactory
初始化ApplicationContextInitializer、ApplicationListener接口实例集合
this.initialMulticaster.multicastEvent( font color=\"#cc0000\
WebServerFactoryCustomizerBeanPostProcessor
SourceClass sourceClass = asSourceClass(configClass);
//获取beanFactory注册的所有类型为BeanDefinitionRegistryPostProcessor.class的beanbeanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class)
ConditionEvaluationReportLoggingListener
配置mainApplicationClass
public void processGroupImports() { for (DeferredImportSelectorGrouping grouping : this.groupings.values()) { //getImports()核心方法 grouping.getImports() .forEach(entry -> { ConfigurationClass configurationClass = this.configurationClasses.get( entry.getMetadata());//处理任何一个 @Import 注解 font color=\"#ff6666\
设置awt-configureHeadlessProperty
cancelRefresh(ex)
标志spring容器已经刷新,此时所有的bean实例都已经加载完毕
从spring.factories配置文件中加载异常报告期实例,这里加载的是FailureAnalyzers
true
//获取beanFactory注册的所有类型为BeanFactoryPostProcessor.class的bean beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class)
根据Order进行排序-AnnotationAwareOrderComparator.sort
循环执行
处理配置类上的注解 @Import
本质注册is instanceof MergedBeanDefinitionPostProcessor接口的全部BeanPostProcessor
try
处理配置类上的注解@PropertySources
// 对加了@Configuration注解的配置类进行Cglib代理 enhanceConfigurationClasses(beanFactory);
遍历全部ApplicationListener
if (isEagerInit) {\t\t\t\t\t\t\tgetBean(beanName);\t\t\t\t\t\t}
初始化所有剩下的单实例bean
ConfigurationClasPostProcessor
完成BeanFactory的初始化创建工作;IOC容器就此创建完成
postProcessApplicationContext(context)
获取Bean的定义信息;RootBeanDefinition
registerBeanPostProcessors(beanFactory);
//遍历candidateNames,筛选出@Configuration标记的Bean,并将将BeanDefinition转换为BeanDefinitionHolder//正常只获得到SpringBoot启动类Bean,但是我们其实是可以通过registryBeanDefinition注册其他@Configuration,SpringBoot程序还没想好在哪里注册
beanFactory.getBean(\"internalAutoProxyCreator\
postProcessBeanFactory(beanFactory)
getBeanFactory().getBean(\"TomcatServletWebServerFactory\
停止stopWatch计时
Bean不是抽象的,是单实例的,不是懒加载
注意如果在第一阶段出现了bean,则跳过本次阶段
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
registerListeners()
refreshContext(context)
第一阶段处理BeanDefinitionRegistryPostProcessors.class
如果使用@EnableAspectJAutoProxy 开启AOP功能,则会创建名为internalAutoProxyCreator的BeanPostProcessor【AnnotationAwareAspectJAutoProxyCreator】对象,以该对象为例
ContextIdApplicationContextInitializer
initPropertySources()
stopWatch.start()
若启动过程中抛出异常,此时用FailureAnalyzers来报告异常
注意传入的resourceLoader参数为null(这里将使用当前线程所在的ClassLoader-ApplicationClassLoader)
font color=\"#ff6666\
getTextBanner(environment)
afterRefresh()
实例化接口实现类-createSpringFactoriesInstances
优先注册实现了PriorityOrdered接口的BeanPostProcessor
if (isFactoryBean(beanName))
ApplicationContext应用一些相关的后置处理,比如设置resourceLoader属性
步骤二
获取属性deferredImportSelectors中记录的DeferredImportSelector
先执行(先排序再执行)实现了PriorityOrdered优先级接口的BeanFactoryPostProcessor、postProcessor.postProcessBeanFactory()
callRunners()
location:spring.banner.image.location;gif、jpg、png
ConfigurationWarningsApplicationContextInitializer
prepareBeanFactory(beanFactory)
若出现异常,此时仅仅报告异常,而不会发射任何事件
postProcessBeforeInitialization
getImageBanner(environment)
getBean(beanName);
List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
run()
向容器中添加BeanFactoryPostProcessor:new CachingMetadataReaderFactoryPostProcessor()
启动tomcat容器initialize()--tomcat.start()
本流程就以Servlet容器的tomcat如何集成到SpringBoot容器为例,说明内置Tomcat启动原理<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> </dependency>
备环境变量,包括系统变量,环境变量,命令行参数,默认变量,servlet相关配置变量,随机值,JNDI属性值,以及配置文件(比如application.properties
处理配置类上的注解 @ComponentScan
initMessageSource()
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
给容器中注册BeanPostProcessorChecker
步骤一
throw ex
内部会异步调用TomcatStrarter的onStartup()方法完成启动
Thread.currentThread().getContextClassLoader()
执行完构造函数触发BeanPostProcessor
if (bean instanceof FactoryBean)
判断webApplicationType
注册相关
模板方法,留给子类重写实现
prepareContex()
SpringWeb定义了SpringServletContainerInitializer实现了,WebApplicationInitializer为扩展点,我们通常extennd AbstractAnnotationConfigDispatcherServletInitializer来完成扩展,抽象类的OnStartup()方法内部的完成了DispatcherServerlet的创建,Listerner、Filter的servletContextb style=\"font-size: inherit;\
循环处理@Configuration注解标记的类,参数为外部指定需要被分析的一组候选配置类
循环处理每个spring.factories
形参说明:beanFactory是DefaultListableBeanFactory,beanFactoryPostProcessors是注册在当前ApplicationContext下的BeanFactoryPostProcessor-instancesinstances
&&
//直接执行子接口的postProcessBeanDefinitionRegistry方法;registryProcessor.postProcessBeanDefinitionRegistry(registry);//便于后续执行父接口postProcessBeanFactory方法;registryProcessors.add(registryProcessor);
构造函数初始化
创建@Configuration类解析器-parser
applicationContext容器中已经存在3个BeanFactoryPostProcessorCachingMetadataReaderFactoryPostProcessorConfigurationWarningsPostProcessorPropertySourceOrderingPostProcessor
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { refreshBeanFactory(); return getBeanFactory(); }
String[] candidateNames = registry.getBeanDefinitionNames();
getSpringFactoriesInstances(Class<T> type)
//先执行(先排序再执行)实现了Ordered优先级接口的BeanDefinitionRegistryPostProcessorpostProcessor.postProcessBeanDefinitionRegistry(registry); //便于后续执行父接口方法;registryProcessors.addAll(currentRegistryProcessors);
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory()
synchronized (this.startupShutdownMonitor){下方全部流程······}
getBanner(Environment environment)
ReactiveWebServerApplicationContext
ServletWebServerApplicationContext
通过StackTraceElement记录的main函数所在的类,即启动类.class
getWebServerFactory方法就是从容器中获取到TomcatServletWebServerFactory类型的bean
AnnotationAwareOrderComparator.sort(allListeners);j将订阅事件的Listen而排序,至此getApplicationListeners()方法体结束
调用监听器的执行监听事件方法
//先执行(先排序再执行)实现了PriorityOrdered优先级接口的BeanDefinitionRegistryPostProcessorpostProcessor.postProcessBeanDefinitionRegistry(registry); //便于后续执行父接口方法;registryProcessors.addAll(currentRegistryProcessors);
处理配置类中每个带有@Bean注解的方法
listeners.running()
配置resourceLoader
new SpringApplication
getBean(beanName)
listeners.starting();
获取上一步parse解析bean的结果
PropertiesLoaderUtils.loadProperties(resource);
初始化MessageSource组件(做国际化功能;消息绑定,消息解析);
prepareRefresh()
注册相关系统Beani、BeanFactoryPostProcessor--ConfigurationClassPostProcessor、EventListenerMethodProcessorii、BeanPostProcessor--AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessoriii、EventListenerFactory--DefaultEventListenerFactory iv、jpa bean(暂忽略)
获取类加载器-getClassLoader
调用ApplicationRunner和CommandLineRunner的run方法,实现spring容器启动后需要做的一些东西比如加载一些业务数据等
applyInitializers(context)
BeanFactory准备工作完成后进行的后置处理工作;留给子类通过重写这个方法来在BeanFactory创建并预准备完成以后做进一步的设置
handler.processGroupImports();
font color=\"#66cc00\
标志SpringApplication已经正在运行即已经成功启动,可以接收服务请求了。
getWebServerFactory()
当前是DefaultListableBeanFactory所以走此处逻辑
//则为父接口实例,暂存起来后面统一执行父接口的postProcessBeanFactory方法regularPostProcessors.add(postProcessor);
ServletWebServerFactoryAutoConfiguration:EmbeddedTomcatEmbeddedJettyEmbeddedUndertow
classLoader.getResources(FACTORIES_RESOURCE_LOCATION)
参见:https://blog.csdn.net/andy_zhang2007/article/details/78549773https://blog.csdn.net/qq_34436819/article/details/100944204https://www.processon.com/view/link/5df05037e4b093b9f778e3f0#maphttps://www.processon.com/view/link/5efc44335653bb2925c2c7db
parser.parse(candidates);
注意由于onrefresh在finishBeanFactoryInitialization前执行,则获取bean时属于第一次执行,后续则以单例存在ioc容器中,finishBeanFactoryInitialization跳过该Bean实例化
向容器中添加BeanFactoryPostProcessor:new ConfigurationWarningsPostProcessor()
configureIgnoreBeanInfo(environment)
postProcessor instanceof BeanDefinitionRegistryPostProcessor
getRunListeners(args)-new SpringApplicationRunListeners(getSpringFactoriesInstances( SpringApplicationRunListener.class)
destroyBeans()
创建Spring容器对象createApplicationContext
preInstantiateSingletons()
afterSingletonsInstantiated
重新接轨SpringBoot,自动装配流程
for (String beanName : candidateNames){```}
最后执行(先排序再执行)没有实现任何优先级或者是顺序接口的BeanFactoryPostProcessor;postProcessor.postProcessBeanFactory()
第二阶段处理BeanFactoryPostProcessors.class
注册BeanPostProcessor,实际上就是创建BeanPostProcessor对象,保存在beanFactory容器中,BeanPostProcessor的单实例对象的创建放在此流程中,要早于finishBeanFactoryInitialization
未完待续·····
1、这里比较有趣的一点是创建bean实例对象的生命周期过程中,执行全部BeanPostProcessor本身就像AOP的思想;2、而且创建BeanProcessor-bean实例对象,也不例外,也要执行beanfactory中现有的全部BeanPostProcessor进行拦截,只不过不会执行自己BeanPostProcesor逻辑,因为还没有加入注册到容器中,正处在注册到容器中的流程。3、后面创建的Bean(包括BeanPostProcessor bean)对象过程中就会被前面已经加入到容器中BeanPostProcessor进行拦截,执行其postProcessBeforeInitialization、postProcessAfterInitialization
Spring((AbstractApplicationContext) applicationContext).refresh()
BeanUtils.instantiateClass()
BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
加载sourcesgetAllSources()-- 这里应该只是把标有@SpringBootApplication注解的启动类注册到容器中
SharedMetadataReaderFactoryContextInitializer
stopWatch.stop()
创建ApplicationArguments对象,封装了args参数
创建ApplicationArguments对象,封装启动类传入的args参数
优先注册实现了Ordered接口的BeanPostProcessor
如果有@Conditional,则获取其value中的Condition.class,调用其matches方法判断是否匹配;
初始化事件派发器
//添加一个BeanPostProcessor后置处理器,Bean后置处理器最终会在Bean实例化和初始化的过程中执行,debug会发现在populateBea()方法的-ibp.postProcessProperties,会调用此PostProcessor beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
处理parse方法中添加到deferredImportSelectors缓存中的DeferredImportSelector类DeferredImportSelector 是 ImportSelector 的一个变种。ImportSelector 被设计成其实和@Import注解的类同样的导入效果,但是实现 ImportSelector的类可以条件性地决定导入哪些配置。DeferredImportSelector 的设计目的是在所有其他的配置类被处理后才处理。这也正是该语句被放到本函数最后一行的原因。
location:spring.banner.location
DelegatingApplicationContextInitializer
initApplicationEventMulticaster()
ServletWebServerApplicationContext、ReactiveWebServerApplicationContext分别重写onRefresh
Bean的元数据AnnotationMetadata,被@Configuration注解标记--该Bean属性设置为Full
this.deferredImportSelectorHandler.process();
//最后执行(先排序再执行)没有实现任何优先级或者是顺序接口的BeanDefinitionRegistryPostProcessorpostProcessor.postProcessBeanDefinitionRegistry(registry); //便于后续执行父接口方法;registryProcessors.addAll(currentRegistryProcessors);
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
processConfigBeanDefinitions(registry)
添加Listeners至派发器中并派发之前流程产生的早起事件
supportsEventType(eventType)
LoggingApplicationListener
doGetBean()
new AnnotationConfigServletWebServerApplicationContext()
用于分析一个 ConfigurationClass,分析之后将它记录到已处理配置类记录
return DEFAULT_BANNER
ReactiveWebServerFactoryAutoConfiguration:EmbeddedTomcatEmbeddedJettyEmbeddedUndertowEmbeddedNetty
applicationContext .addApplicationListener(new ConditionEvaluationReportListener())
配置spring.beaninfo.ignore属性,默认为true,即跳过搜索BeanInfo classes.
ConfigFileApplicationListener
是否实现了FactoryBean接口
BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor是父子接口继承关系 @FunctionalInterface public interface BeanFactoryPostProcessor { void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException; } public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor { void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException; }
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit())
为容器对象内属性-设置environment属性
将配置好的tomcat传入,返回一个webserver,getTomcatWebServer(tomcat)
public Iterable<Group.Entry> getImports() { for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {//注意这里是核心方法,SpringBoot自动配置的入口方法//this.group.process方法,为DeferredImportSelector接口的内部Group接口中定义的方法,DeferredImportSelector-Group接口的其实现类之一刚好是AutoConfigurationImportSelector-AutoConfigurationGroup类this.group=AutoConfigurationImportSelecto中AutoConfigurationGroup类 font color=\"#ff6666\
再执行(先排序再执行)实现了Ordered顺序接口的BeanFactoryPostProcessor;postProcessor.postProcessBeanFactory()
if (banners.hasAtLeastOneBanner())
检查父类是否需要处理,如果父类需要处理返回父类,否则返回null
根据classpath中存在哪种类型的类来确定是哪种应用类型:REACTIVE、SERVLET、NONE
遍历形参beanFactoryPostProcessors
封装成new GenericApplicationListenerAdapter(listener))
createWebServer()
ServerPortInfoApplicationContextInitializer
配置primarySources
打印Banner-printBanner(environment)
给容器中注册ApplicationListenerDetector
获取所有的定制器WebServerFactoryCustomizer,内置比如ServletWebServerFactoryCustomizer和自定义的定制器
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
this.webServer = factory.getWebServer(getSelfInitializer())
当前listener是否是 GenericApplicationListener类型
需要被处理的配置类configClass已经被分析处理,将它记录到已处理配置类记录
new AnnotatedBeanDefinitionReader(this);
this.fallbackBanner != null
beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory))
Bean的元数据AnnotationMetadata,被@Component、@ComponentScan、@Import、@ImportResource标记、或者含有@Bean标记的方法--该Bean属性设置为Lite
循环
cache.get(classLoader)
1、依据泛型接口的泛型参数,i、参数为具体的Event如ApplicationStartingEvent,监听单一事件,如LiquibaseServiceLocatorApplicationListenerii、参数为父类SpringApplicationEvent,则监听多个子类事件,如BackgroundPreinitializeriii、参数为基类ApplicationEvent,则监听全部事件如,DelegatingApplicationListener、LoggingApplicationListener2、Order值越小,越先执行,Order设置方式i、基于注解@Order(LoggingApplicationListener.DEFAULT_ORDER + 1)ii、实现接口,implements Ordered iii、如果使用配置文件方式创建的监听器,则该监听器最优先执行3、在Spring框架中提供了两种事件监听的方式:i、编程式:通过实现ApplicationListener接口来监听指定类型的事件ii、注解式:通过在方法上加@EventListener注解的方式监听指定参数类型的事件,写该类需要托管到Spring容器中 在SpringBoot应用中还可以通过配置的方式实现监听:iii、通过application.properties中配置context.listener.classes属性指定监听器 参见:https://www.cnblogs.com/ashleyboy/p/9566579.htmlhttps://www.cnblogs.com/RPlandscape/p/10036551.html
Exception
向容器中注册springApplicationArguments、springBootBanner
applicationContext.addApplicationListener(this)
beanFactory.registerSingleton(\"springBootLoggingSystem\
this.reader.loadBeanDefinitions(configClasses);
获取容器中的所有BeanNames,this-DefaultListableFactory
do { sourceClass = font color=\"#ff6666\
处理配置类所实现接口的缺省方法
context.setEnvironment(environment)
获取配置文件中的port等值,为TomcatServletWebServerFactoryServletWebServerFactoryCustomizer.java{ private final ServerProperties serverProperties; public ServletWebServerFactoryCustomizer(ServerProperties serverProperties) { this.serverProperties = serverProperties; } public void customize(ConfigurableServletWebServerFactory factory) { PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull(); map.from(this.serverProperties::getPort).to(factory::setPort); }}
cache==null
0 条评论
下一页