本文已收录【修炼内功】跃迁之路

微信关注“林中小舍”,林小二带你聊技术!

上篇文章 Spring Framework中的注解是如何运作的 介绍了Spring Framework中各种注解的运作形式,(在SpringBoot推出之前)对于组件的应用还须要手动进行配置(无论xml/groovy文件形式还是注解形式),如DataSource、SessionFactory、TransactionManager、DispatcherServlet等等

SpringBoot提供了一种新的形式用于简化Spring利用的搭建及开发过程,通过各种starter实现组件的主动拆卸(autoconfig),将约定优于配置体现的酣畅淋漓,在此基础上还提供了泛滥扩大点用以批改约定的配置及默认的组件性能

那,SpringBoot是如何实现主动拆卸的?(SpringBoot提供的starter列表见 Using boot starter)

疾速生成Boot利用

  • SpringBoot脚手架:https://start.spring.io/
  • PandoraBoot脚手架(阿里外部):http://mw.alibaba-inc.com/boo...

SpringBoot的启动

SpringBoot利用个别会将 SpringApplication@SpringBootApplication 放一起配合应用

@SpringBootApplicationpublic class Application {    public static void main(String[] args) {            SpringApplication app = new SpringApplication(Application.class);        app.setWebApplicationType(WebApplicationType.NONE);        app.run(args);        // 或者        // SpringApplication.run(Application.class, args);        // 或者        // new SpringApplicationBuilder(Application.class)        //        .profiles("dev")        //        .properties("spring.application.name=spring-boot-demo")        //        .run(args);    }}
这里,不肯定非要应用@SpringBootApplication注解,SpringApplication也不肯定非要放在main入口中

在此,将SpringApplication及@SpringBootApplication的作用分两个小结详解

上例中展现了三种SpringApplication的编码方式,但不管何种形式都离不开两个步骤:创立(SpringApplication#new);运行(SpringApplication#run)

SpringApplication创立

在SpringApplication创立过程中初始化了一些参数,各参数的作用/应用会在下文中得以解释

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {    // ResourceLoader    this.resourceLoader = resourceLoader;    // 主入口类    this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));    // web类型 NONE | SERVLET | REACTIVE    this.webApplicationType = WebApplicationType.deduceFromClasspath();    // 设置initializers(org.springframework.context.ApplicationContextInitializer)    setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));    // 设置listeners(org.springframework.context.ApplicationListener)    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));    // main函数所处的类    this.mainApplicationClass = deduceMainApplicationClass();}

这里须要着重介绍的是在初始化某些参数时应用的一些逻辑

web类型的探测

web类型的探测用到了WebApplicationType#deduceFromClasspath,其逻辑如下

或者你也遇到过相似的状况,自身并不是一个web工程,却因为某些起因(如引入第三方包的不标准)导致探测到了REACTIVE/SERVLET从而进入了web启动流程(ReactiveWebServerApplicationContext / ServletWebServerApplicationContext)进而引发其余的问题

spring.factories文件初探

Java中SPI(Service Provider Interface)的概念或者各位都不生疏,其提供了一套用来被第三方实现或者扩大的API,用以启用框架扩大、替换组件,将拆卸的控制权移到程序之外(如最为典型的 jdbc dirver)

Spring中大量应用了该思维,spring.factories是其一种实现模式,spring.factories外围加载逻辑在SpringFactoriesLoader#loadFactoryNames / SpringFactoriesLoader#loadSpringFactories

以spring-boot中spring.factories片段为例

# PropertySource Loadersorg.springframework.boot.env.PropertySourceLoader=\org.springframework.boot.env.PropertiesPropertySourceLoader,\org.springframework.boot.env.YamlPropertySourceLoader# Run Listenersorg.springframework.boot.SpringApplicationRunListener=\org.springframework.boot.context.event.EventPublishingRunListener

SpringFactoriesLoader#loadSpringFactories加载后的Map,key为等号前的接口类,value为等号后的实现类列表

再次回到SpringApplication创立过程中对initializerslisteners的初始化,其别离加载并初始化了spring.factories文件中的org.springframework.context.ApplicationContextInitializerorg.springframework.context.ApplicationListener

Java SPI及Spring Factories的几点比照如下

Java SPISpring Factories
文件地位META-INF/services/{interface full class name}META-INF/spring.factories
文件内容每行一个接口实现类,能够多行properties文件格式,key为接口类全门路,value为实现类全门路(多个间应用逗号分隔)
加载办法ServiceLoader#loadSpringFactoriesLoader#loadFactoryNames/#loadFactories

Q&A

  • 是否能够自定义META-INF/spring.factories,用以扩大Spring中用到的组件?

    能够,事实上Spring也激励这样做

  • 是否能够应用META-INF/spring.factories实现本人的逻辑?

    能够,SpringFactoriesLoader中的办法为公开的,并且SpringFactoriesLoader的实现在spring-core中,其应用并不局限于spring-boot

注:应用SpringFactorieLoader加载并初始化的实例通常并没有被IOC治理,通常也没有实现依赖注入的能力

参考 SpringFactoriesLoader#loadFactories / SpringApplication#createSpringFactoriesInstances

主main函数入口类探测

mainApplicationClass用以记录main函数所在类,其探测实现在SpringApplication#deduceMainApplicationClass,逻辑则略显“奇巧”,通过结构RuntimeException获取其stackTrace,剖析每一个StackTraceElement找到调用链上的main函数,并返回该函数所在类

对于mainApplicationClass的作用会在下文介绍

SpringApplication启动

SpringApplication的启动过程要比创立过程切实的多

SpringApplicationRunListener配置在spring.factories中,其能够针对SpringBoot启动过程中的各事件进行监听(详见SpringApplicationRunListener中的办法定义)

Spring盘根错节的逻辑关系难以在一张流程图中理清所有,常规,将其拆分并各个击破

ApplicationArguments

在启动jvm时通常能够增加一些启动参数,诸如-jar-XX:CMSTriggerRatio-Dproperty以及自定义参数等

通常有两种参数能够被Spring应用,-Dproperty=value 及--property=value

前者为jvm的能力,其将具体的参数值设置到零碎参数中,以便任意的框架均可通过System#getProperty获取

-Dproperty=value

Sets a system property value. The property variable is a string with no spaces that represents the name of the property. The value variable is a string that represents the value of the property. If value is a string with spaces, then enclose it in quotation marks (for example -Dfoo="foo bar").

https://docs.oracle.com/javas...

后者为spring的能力,其底层应用SimpleCommandLinePropertySource来解析,在SpringBoot利用中还能够通过bean-type或bean-name(“springApplicationArguments”)来注入ApplicationArguments,以便在本人的逻辑中获取--property=value类型的启动参数

结构Environment

org.springframework.boot.SpringApplication#prepareEnvironment

流程图中ConversionService的作用能够参考org.springframework.beans.TypeConverter的应用(Bean是如何被创立的)

同时Spring会将启动参数中的-Dproperty=value 及--property=value一并合并到Environment中

Environment创立过程中会将SystemProperties及SystemEnvironment一并合并到Environment中

见AbstractEnvironment#new及StandardEnvironment#customizePropertySources

留神到,application配置文件中spring.main.*下的配置能够批改SpringApplication中的参数,如

spring.main.log-startup-info=falsespring.main.lazy-initialization=truespring.main.banner-mode=LOG# 见SpringApplication中反对的参数设置# https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features
Binder的应用见Property Binding in Spring Boot 2.0

输入Banner

org.springframework.boot.SpringApplication#printBanner

通常在Spring启动时会看到诸如下图的banner,其实spring是提供了弱小定制能力的,具体应用能够参考Customizing the Banner

Spring同时反对文本(间接输入文本内容)及图片(将图片解析为文本进行绘制)两种banner能力,其别离通过ResourceBanner及ImageBanner实现,具体见SpringApplicationBannerPrinter#getBanner

结构ApplicationContext

org.springframework.boot.SpringApplication#createApplicationContext

这里并没有太多须要介绍的,spring会依据webApplicationType生成不同的ApplicationContext

webApplicationTypeApplicationContext
WebApplicationType.SERVLETAnnotationConfigServletWebServerApplicationContext
WebApplicationType.REACTIVEAnnotationConfigReactiveWebServerApplicationContext
默认AnnotationConfigApplicationContext

ApplicationContext初始化前

org.springframework.boot.SpringApplication#prepareContext

这里须要重点介绍几个逻辑

ApplicationContextInitializer#initialize

文章开始初介绍了Spring会从spring.factories中加载ApplicationContextInitializer,在这里则会用到它们的initialize办法,通常能够通过该办法注册一些额定的bean或者BeanFactoryPostProcessor,甚至对ApplicationContext做一些批改

如spring-boot-autoconfiguration中注册的SharedMetadataReaderFactoryContextInitializer

class SharedMetadataReaderFactoryContextInitializer        implements ApplicationContextInitializer<ConfigurableApplicationContext> {    @Override    public void initialize(ConfigurableApplicationContext applicationContext) {        applicationContext.addBeanFactoryPostProcessor(new CachingMetadataReaderFactoryPostProcessor());    }}

再如spring-boot-devtools中注册的RestartScopeInitializer

public class RestartScopeInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {    @Override    public void initialize(ConfigurableApplicationContext applicationContext) {        applicationContext.getBeanFactory().registerScope("restart", new RestartScope());    }}

lazyInitialization

如果该属性被设置为true,spring则会向ApplicationContext中增加LazyInitializationBeanFactoryPostProcessor,其会将所有bean的lazyInit属性设置为true,以提早bean的加载并放慢SpringBoot的启动速度,其弊病则是将一些隐性的谬误提早到了首次加载阶段(如注入问题)

A downside of lazy initialization is that it can delay the discovery of a problem with the application.

当然也有例外情况,可通过注册LazyInitializationExcludeFilter进行排除实现

primarySources及sources的加载

primarySources可通过SpringApplication的结构传入,sources可通过spring.main.sources设置

通常咱们须要将@SpringBootApplication注解增加到primarySource或source类上,其目标就是在加载primarySources或sources时一并解析

SpringApplication的启动逻辑(run函数)并不是SpringBoot的全副,其大部分性能由@SpringBootApplication注解代入

至此还没有执行ApplicationContext的refresh动作,也就是说primarySources及sources(如果存在则包含@SpringBootApplication)的解析是优先于ApplicationContext#refresh的

当然,实践上能够将@SpringBootApplication注解放到其余类上,但请保障该类能够被Spring扫描到

ApplicationContext的初始化

org.springframework.boot.SpringApplication#refreshContext

该局部没有非常特地的逻辑,执行ApplicationContext的refresh办法并注册shutdown hook(registerShutdownHook)

ApplicationContext的refresh逻辑参考ApplicationContext给开发者提供了哪些(默认)扩大

ApplicationContext初始化后

org.springframework.boot.SpringApplication#afterRefresh

该局部并没有理论的实现,由子类实现

异样解决

org.springframework.boot.SpringApplication#handleRunFailure

在SpringApplication启动过程中产生异样则有此局部解决,这里须要关注的是,具体的异样可由SpringBootExceptionReporter#reportException接管并解决

而SpringBootExceptionReporter则由spring.factories中的org.springframework.boot.SpringBootExceptionReporter进行注册(通常为org.springframework.boot.diagnostics.FailureAnalyzers)


至此实现了SpringApplication的初始化及执行过程的介绍,但对于泛滥SpringBoot的能力貌似都没有体现,正如上文所述,SpringBoot大部分性能由@SpringBootApplication注解代入

@SpringBootApplication注解的威力

如上文介绍,通常须要将@SpringBootApplication注解增加到primarySource或source类上,其目标是在加载primarySources或sources时一并解析,并且此过程个别在ApplicationContext refresh之前

对于注解的解析逻辑见 Spring Framework中的注解是如何运作的

首先看一下@SpringBootApplication注解的层级构造咱们对其进行拆分并顺次介绍其作用

ComponentScan

在 Spring Framework中的注解是如何运作的一文中有介绍,如果@ComponentScan中没有指定任何扫描packages,Spring则会应用指标class所在的package进行扫描,这也是为什么咱们在@SpringBootApplication上没有指定scanBasePackages时,总是会扫描@SpringBootApplication润饰类所在package的起因

此外,@SpringBootApplication中默认为@ComponentScan增加了两个excludeFilter,TypeExcludeFilterAutoConfigurationExcludeFilter

前者的排除规定由TypeExcludeFilter类型的bean实现,可自行实现并注册

后者则为了避免primarySource与spring.factories中org.springframework.boot.autoconfigure.EnableAutoConfiguration同时指定一个类时的反复注册

SpringBootConfiguration

该注解仅是简略继承了@Configuration,@Configuration介绍详见 Spring Framework中的注解是如何运作的

EnableAutoConfiguration

@EnableAutoConfiguration注解次要用来发现须要拆卸的配置类,并进行主动拆卸

该注解应用@Import间接导入了AutoConfigurationImportSelector,同时继承了@AutoConfigurationPackage,而@AutoConfigurationPackage也简略地应用@Import导入了AutoConfigurationPackages.Registrar

这里咱们对导入的两个类进行剖析(@Import的介绍详见 Spring Framework中的注解是如何运作的)

AutoConfigurationImportSelector

AutoConfigurationImportSelector#selectImports

该注册器的逻辑其实非常简单

  • spring.factories中org.springframework.boot.autoconfigure.EnableAutoConfiguration记录了所有须要注册的配置类
  • @EnableAutoConfiguration中的exclude及excludeName参数,及spring.autoconfigure.exclude,配置了不须要注册的配置类信息
  • spring-autoconfigure-metadata.properties中记录了各种配置类的注册条件

依据以上信息,能够筛选出最终须要注册的配置类,并对其进行配置

spring.factories中org.springframework.boot.autoconfigure.EnableAutoConfiguration,示例如

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration

spring-boot-autoconfigure工程中的spring.factories文件中定义了大量的XxxAutoConfiguration,用以在引入不同starter时对相干Bean的主动拆卸(SpringBoot提供的starter列表见 Using boot starter)

spring-boot-autoconfigure工程中的spring.factories文件定义了spring-boot绝大部分starter主动拆卸的XxxAutoConfiguration,但通常来讲并不是所有的XxxAutoConfiguration都须要拆卸

决定一个XxxAutoConfiguration是否须要进行拆卸,由以下几方面管制

  • @EnableAutoConfiguration参数管制
  • spring.autoconfigure.exclude参数管制
  • spring-autoconfigure-metadata.properties文件中指定的规定管制
  • XxxAutoConfiguration自身的条件管制,如硬编码的@ConditionalOn

spring-autoconfigure-metadata.properties文件,示例如

org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration.AutoConfigureAfter=org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfigurationorg.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration.ConditionalOnClass=com.datastax.driver.core.Cluster,reactor.core.publisher.Flux,org.springframework.data.cassandra.core.ReactiveCassandraTemplateorg.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration.ConditionalOnWebApplication=SERVLETorg.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration.AutoConfigureOrder=-2147483648

该文件定义了各种配置类主动拆卸的条件,properties文件的格局为&dollar;{配置类全门路}.&dollar;{条件类型}=&dollar;{条件值}

条件类型能够为ConditionalOnClass、AutoConfigureAfter、AutoConfigureOrder等,其逻辑由org.springframework.boot.autoconfigure.AutoConfigurationImportFilter定义解析,AutoConfigurationImportFilter同样在spring.factories中指定

Q: 如何借助spring.factories在SpringBoot启动时主动拆卸自定义的Bean(s)? 如何应用该个性自定义starter?

Q&A:

SpringBoot是如何通过@AutoConfigureBefore、@AutoConfigureAfter、AutoConfigureOrder管制配置类加载程序的?

AutoConfigurationImportSelector实现了DeferredImportSelector(DeferredImportSelector的原理参考Spring Framework中的注解是如何运作的),其在ConfigurationClassParser#deferredImportSelectorHandler.process()阶段,应用AutoConfigurationSorter针对以上注解对配置类进行了加载的排序

  • AutoConfigurationImportSelector.AutoConfigurationGroup#selectImports
  • AutoConfigurationImportSelector.AutoConfigurationGroup#sortAutoConfigurations

AutoConfigurationPackages.Registrar

AutoConfigurationPackages.Registrar#registerBeanDefinitions

该注册器的逻辑则略显薄弱,其注册了一个名为org.springframework.boot.autoconfigure.AutoConfigurationPackages类型为BasePackages的bean,该bean中记录了被@EnableAutoConfiguration润饰的类所在的package

ConfigurationPropertiesScan

@ConfigurationPropertiesScan次要用来发现@ConfigurationProperties,并对其进行解析、注册

同样的,该注解应用@Import间接导入了ConfigurationPropertiesScanRegistrar,同时继承了@EnableConfigurationProperties,而@EnableConfigurationProperties也简略地应用@Import导入了@EnableConfigurationPropertiesRegistrar

这里咱们对导入的两个类进行剖析

ConfigurationPropertiesScanRegistrar

ConfigurationPropertiesScanRegistrar#registerBeanDefinitions

该局部逻辑比较简单,不再附以流程图

@Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {    // 从@ConfigurationPropertiesScan中获取须要扫描packages    Set<String> packagesToScan = getPackagesToScan(importingClassMetadata);    // 在指定packages中扫描被@ConfigurationProperties润饰的类并注册    scan(registry, packagesToScan);}

所以整体逻辑

  1. 从@ConfigurationPropertiesScan中(basePackages/basePackageClasses)获取须要扫描的packages,如果均为指定则默认@ConfigurationPropertiesScan润饰类所在package
  2. 在以上package中扫描被@ConfigurationProperties润饰的类并注册,扫描器由ClassPathScanningCandidateComponentProvider创立

以上具体逻辑可浏览源码,扫描逻辑可参考Spring Framework中的注解是如何运作的 - ClassPathBeanDefinitionScanner

EnableConfigurationPropertiesRegistrar

EnableConfigurationPropertiesRegistrar#registerBeanDefinitions

@ConfigurationPropertiesScanRegistrar只是用来在指定packages中发现@ConfigurationProperties并注册,那@ConfigurationProperties的具体解析在哪里?
@Overridepublic void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {    // 注册处理器    registerInfrastructureBeans(registry);    // 对@EnableConfigurationProperties中指定的类进行注册    ConfigurationPropertiesBeanRegistrar beanRegistrar = new ConfigurationPropertiesBeanRegistrar(registry);    getTypes(metadata).forEach(beanRegistrar::register);}

EnableConfigurationPropertiesRegistrar做了两件事

  1. @EnableConfigurationProperties#value能够间接指定被@ConfigurationProperties润饰的类,EnableConfigurationPropertiesRegistrar对其进行注册(注册逻辑可参考Spring Framework中的注解是如何运作的 - AnnotatedBeanDefinitionReader)
  2. 注册一些处理器(以下仅列出其中比拟要害的几个处理器)

    • ConfigurationPropertiesBindingPostProcessor
    • ConfigurationPropertiesBinder

ConfigurationPropertiesBinder

ConfigurationPropertiesBinder是一个通用能力,底层采纳Binder(见Property Binding in Spring Boot 2.0)将@ConfigurationProperties中指定的规定属性绑定到润饰的Bean实例中

ConfigurationPropertiesBindingPostProcessor

ConfigurationPropertiesBindingPostProcessor实现了BeanPostProcessor,在其postProcessBeforeInitialization函数中借助ConfigurationPropertiesBinder对@ConfigurationProperties润饰的Bean做属性绑定动作(BeanPostPocessor原理参考Bean是如何被创立的)

通常@ConfigurationProperties与@NestedConfigurationProperty配合应用,解决简单对象属性绑定

参考Nested Properties

starter中应用@ConfigurationProperties绑定属性时,为了疾速让使用者理解starter能够进行配置的选项,以及辅助IDE在配置时进行提醒、校验、主动补全等,会应用spring-boot-configuration-processor将@ConfigurationProperties所在类的信息映射为元数据文件(META-INF/spring-configuration-metadata.json)

其中形容信息来自规范的javadoc(参考Generating Your Own Metadata by Using the Annotation Processor)

回顾

回顾一下@SpringBootApplication注解的层级构造

Spring Framework中的注解是如何运作的中有介绍Spring中的注解编程模型,@SpringBootApplication由很多注解组合而成,并且在其中重写了@EnableAutoConfiguration及@ComponentScan的参数,以便在@SpringBootApplication中间接管制后者的参数

是否有曾思考过,@SpringBootApplication所蕴含的注解只能以@SpringBootApplication的形式应用么?是否能够独自应用?@SpringBootApplication并没有重写@ConfigurationPropertiesScan及@EnableConfigurationProperties注解参数,那后者的参数如何管制?

凡事不必太过死板,@SpringBootApplication仅仅整合了多个注解的能力,至于组合应用还是独自应用齐全由开发者决定,这也是Spring比拟敌对的中央

对于Bean属性绑定而言,反而比拟罕用的是@ConfigurationProperties与@EnableConfigurationProperties的组合,而不是@SpringBootApplication,尤其在starter的实现中

@ConfigurationProperties(prefix = "spring.my", ignoreInvalidFields = true)public class MyProperties { ... }@Configuration@EnableConfigurationProperties(MyProperties.class)public class MyConfiguration { ... }
Q: 是否还有其余发现?

spring.factories浅解

SpringBoot中spring.factories内容十分丰盛,这里筛选几个有代表性的进行梳理,更多的内容还须要读者自行摸索

spring-boot

SpringApplicationRunListener

org.springframework.boot.SpringApplicationRunListener (on spring.factories)

上文有介绍,SpringApplicationRunListener能够针对SpringBoot启动过程中的各事件进行监听,其中比拟有代表性的EventPublishingRunListener,其在contextLoaded阶段(EventPublishingRunListener#contextLoaded)将spring.factories中配置的ApplicationListener增加到创立的ApplicationContext中

ApplicationListener

org.springframework.context.ApplicationListener (on spring.factories)

ApplicationListener的应用在ApplicationContext给开发者提供了哪些(默认)扩大中有介绍,ApplicationListener的注册也能够在spring.factories中,这里要介绍的一个ApplicationListener是ConfigFileApplicationListener,其在ApplicationEnvironmentPreparedEvent事件(ConfigFileApplicationListener#onApplicationEnvironmentPreparedEvent)下加载了spring.factories中所有的EnvironmentPostProcessor,执行其postProcessEnvironment办法对Environment进行加强

EnvironmentPostProcessor

org.springframework.boot.env.EnvironmentPostProcessor (on spring.factories)

从命名上能够看出,EnvironmentPostProcessor是在Environment筹备好后对Environment做一些解决

ConfigFileApplicationListener除了实现ApplicationListener之外同时还实现了EnvironmentPostProcessor,在其postProcessEnvironment办法中加载了spring.factories中所有的PropertySourceLoader,将classpath:/,classpath:/config/,file:./,file:./config/下的 application.* 相似的文件加载到Environment中

PropertySourceLoader

org.springframework.boot.env.PropertySourceLoader

PropertySourceLoader则是用来加载配置文件的具体实现,SpringBoot spring.factories中提供了两种实现 PropertiesPropertySourceLoader及YamlPropertySourceLoader,前者用来加载propertiesxml文件,后者用来加载yml文件

从这里能够看出,通过 (on spring.factories)

  1. EventPublishingRunListener(SpringApplicationRunListener)->
  2. ConfigFileApplicationListener(ApplicationListener)->
  3. ConfigFileApplicationListener(EnvironmentPostProcessor)->
  4. Properties/YamlPropertySourceLoader(PropertySourceLoader)

才实现了application.properties / application.yml配置文件的加载

spring.factories所提供服务的体系比拟宏大,其在SpringBoot主动拆卸中起到了至关重要的作用

Q: 如何实现本人的PropertySourceLoader,实现自定义application.*文件的加载

Q: 理解SpringBoot提供的spring.factories内的性能,并对其进行扩大

spring-autoconfigure

EnableAutoConfiguration

org.springframework.boot.autoconfigure.EnableAutoConfiguration

用来定义须要导入的配置类,SpringBoot starter应用该形式实现配置类的主动导入

AutoConfigurationImportFilter

org.springframework.boot.autoconfigure.AutoConfigurationImportFilter

用来实现相似@Conditional的性能,判断指标配置类是否满足导入条件

SpringBoot提供了OnBeanCondition、OnClassCondition、OnWebApplicationCondition三种Condition,别离解决

  • OnBeanCondition

    @ConditionalOnBean、@ConditionalOnMissingBean、@ConditionalOnSingleCandidate

  • OnClassCondition

    @ConditionalOnClass、@ConditionalOnMissingClass

  • OnWebApplicationCondition

    @ConditionalOnWebApplication、@ConditionalOnNotWebApplication

等注解的解决

后记

SpringBoot的内容远不止这些,SpringBoot所能实现的性能也远超我目前对它的意识,Spring很弱小,但也有它本身的毛病,当下不乏一些优良的竞争对手

语言与框架只是你迈高低一级台阶的工具和伎俩,匠人精力不能少,但也要正确看待当今疾速变动的世界