日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

SpringBoot(2.4.0)自动配置原理(源码)

發(fā)布時間:2025/3/15 javascript 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 SpringBoot(2.4.0)自动配置原理(源码) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

一、從@SpringBootApplication講起

  • 源碼
  • @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan(excludeFilters = {@Filter(type = FilterType.CUSTOM,classes = {TypeExcludeFilter.class} ), @Filter(type = FilterType.CUSTOM,classes = {AutoConfigurationExcludeFilter.class} )} ) public @interface SpringBootApplication {..... }

    出現(xiàn)3個重要注解:

    • @SpringBootConfiguration
    • @EnableAutoConfiguration
    • @ComponentScan

    二、@SpringBootConfiguration(標(biāo)注當(dāng)前類是配置類)

    為什么@SpringBootApplication注解里沒有包含@Configuration,實(shí)際上是在@SpringBootConfiguration里面。

  • 源碼:
  • @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Configuration public @interface SpringBootConfiguration {@AliasFor(annotation = Configuration.class)boolean proxyBeanMethods() default true; }

    @SpringBootConfiguration繼承自@Configuration,二者功能也一致,標(biāo)注當(dāng)前類是配置類,
    并會將當(dāng)前類內(nèi)聲明的一個或多個以@Bean注解標(biāo)記的方法的實(shí)例納入到spring容器中,并且實(shí)例名就是方法名。實(shí)際上如果我們使用如下的Springboot啟動類,整個SpringBoot應(yīng)用依然可以與之前的啟動類功能對等。

    @Configuration @EnableAutoConfiguration @ComponentScan public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);} }

    三、@EnableAutoConfiguration(根據(jù)類路徑下的jar包依賴為當(dāng)前項(xiàng)目進(jìn)行自動配置)

  • 若看過Spring框架的源碼,是否記得spring框架提供的各種名字為@Enable開頭的Annotation定義?
    比如@EnableScheduling,@EnableCaching,@EnableMBeanExport等@EnableAutoConfiguration的理念和"做事方式"其實(shí)一脈相承,借助@Import的支持,收集和注冊特定場景相關(guān)的bean定義:
    • @EnableScheduling是通過@Import將Spring調(diào)度框架相關(guān)的bean定義都加載到Ioc容器中。
    • @EnableMBeanExport是通過@Import將JMX相關(guān)的bean定義加載到Ioc容器
    • @EnableAutoConfiguration也是借助@Import的幫助,將所有符合自動配置條件的bean定義加載到Ioc容器,僅此而已
  • @EnableAutoConfiguration源碼
  • @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import({AutoConfigurationImportSelector.class}) public @interface EnableAutoConfiguration {String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";Class<?>[] exclude() default {};String[] excludeName() default {}; }

    @AutoConfigurationPackage,@Import({AutoConfigurationImportSelector.class})又得好好研究

  • @AutoConfigurationPackage(自動配置包?指定默認(rèn)包規(guī)則)
    • 它指定了默認(rèn)的包規(guī)則
    • 源碼:
    @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @Import({Registrar.class}) //利用Registrar給容器中導(dǎo)入一系列組件 //將指定的一個包下的所有組件導(dǎo)入進(jìn)來,也即是MainApplication 所在包下。 public @interface AutoConfigurationPackage {String[] basePackages() default {};Class<?>[] basePackageClasses() default {}; }

    那就要看看Registrar這個類了:
    里面這段代碼,就是批量注冊:

    static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {Registrar() {}public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {//這里就是利用元注解,獲取到元注解所作用在的類(其實(shí)就是main方法,如下圖)的包名//然后,將其包名下的所有使用了@Configuration注解的類一并加載進(jìn)來AutoConfigurationPackages.register(registry, (String[])(new AutoConfigurationPackages.PackageImports(metadata)).getPackageNames().toArray(new String[0]));}public Set<Object> determineImports(AnnotationMetadata metadata) {return Collections.singleton(new AutoConfigurationPackages.PackageImports(metadata));}}

  • @Import({AutoConfigurationImportSelector.class})
    • AutoConfigurationImportSelector.class有一個 selectImports方法
    //該方法就是規(guī)定要導(dǎo)入哪些包public String[] selectImports(AnnotationMetadata annotationMetadata) {if (!this.isEnabled(annotationMetadata)) {return NO_IMPORTS;} else {AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());}}

    可以看到,核心就是getAutoConfigurationEntry方法,進(jìn)去看一下:


    我們又發(fā)現(xiàn),configurations的獲得是依賴getCandidateConfigurations方法的,進(jìn)去看看,就可以看到自動配置的幕后英雄:SpringFactoriesLoader

    自動配置的幕后英雄:SpringFactoriesLoader

    SpringFactoriesLoader的主要功能就是從指定的配置文件META/spring.factories加載配置,spring.factories是一個典型的java properties文件,配置格式為Key-Value形式,只不過Key和Value都是Java類型的完整類名。
    進(jìn)入loadFactoryNames()方法,就發(fā)現(xiàn)loadFactoryNames()讀取了ClassPath下面的 META-INF/spring.factories 文件。

    @EnableAutoConfiguration的場景中,它更多是提供一種配置查找的功能支持,即根據(jù)@EnableAutoConfiguration的完整類名org.springframework.boot.autoconfigure.EnableAutoConfiguration作為查找的key,獲取對應(yīng)的一組@Configuration類

    • 總結(jié):
    • 1、利用getAutoConfigurationEntry(annotationMetadata);給容器中批量導(dǎo)入一些組件
    • 2、調(diào)用List configurations = getCandidateConfigurations(annotationMetadata, attributes)獲取到所有需要導(dǎo)入到容器中的配置類
    • 3、利用工廠加載 Map<String, List> loadSpringFactories(@Nullable ClassLoader classLoader);得到所有的組件
    • 4、從META-INF/spring.factories位置來加載一個文件。默認(rèn)掃描我們當(dāng)前系統(tǒng)里面所有META-INF/spring.factories位置的文件
      spring-boot-autoconfigure-2.4.0.RELEASE.jar包里面也有META-INF/spring.factories
    • 在spring-boot-autoconfigure-2.4.0.RELEASE.jar包里的META-INF/spring.factories文件,寫死了spring-boot一啟動就要給容器中加載的所有配置類,但是你我肯定都知道,不會一下子加載那么多,那么就是另一個內(nèi)容了:按需加載

    • 開啟按需加載
      SpringBoot自動配置是需要滿足相應(yīng)的條件才會自動配置,因此SpringBoot的自動配置大量應(yīng)用了條件注解ConditionalOnXXX。如下圖:

      上面這些注解會被使用在各個組件上面,然后會根據(jù)環(huán)境決定是否導(dǎo)入各個組件,實(shí)現(xiàn)按需導(dǎo)入,源碼分析

    四、@ComponentScan (自動掃描并加載符合條件的組件或者bean定義)

    @ComponentScan的功能其實(shí)就是自動掃描并加載符合條件的組件或bean定義,最終將這些bean定義加載到容器中。我們可以通過basePackages等屬性指定@ComponentScan自動掃描的范圍,如果不指定,則默認(rèn)Spring框架實(shí)現(xiàn)從聲明@ComponentScan所在類的package進(jìn)行掃描,默認(rèn)情況下是不指定的,所以SpringBoot的啟動類最好放在root package下。

    五、SpringBootApplication注解中4個方法

    @SpringBootApplication不僅包括上面的三個重要注解,還包含有4個方法:

    • Class<?>[] exclude() default {}; 根據(jù)Class來排除特定的類加入Spring容器,傳入?yún)?shù)是class類型
    • String[] excludeName() default {}; 根據(jù)Class name排除特定的類加入spring容器,傳入?yún)?shù)是class的全類名字符串?dāng)?shù)組
    • String[] scanBasePackages() default {};指定掃描包,參數(shù)是包名的字符串?dāng)?shù)組
    • Class<?>[] scanBasePackageClasses() default {};指定掃描包,參數(shù)是Class類型數(shù)組

    六、修改組件默認(rèn)配置

  • SpringBoot默認(rèn)會在底層配好所有的組件。但是如果用戶自己配置了以用戶的優(yōu)先

    平時我們都是直接再寫一個bean注入到容器的

  • 其實(shí)直接修改配置文件就好了。
    原理如下:源碼以HttpEncodingAutoConfiguration為例:

    @Configuration(proxyBeanMethods = false ) @EnableConfigurationProperties({ServerProperties.class}) @ConditionalOnWebApplication(type = Type.SERVLET ) @ConditionalOnClass({CharacterEncodingFilter.class}) @ConditionalOnProperty(prefix = "server.servlet.encoding",value = {"enabled"},matchIfMissing = true ) public class HttpEncodingAutoConfiguration {private final Encoding properties;public HttpEncodingAutoConfiguration(ServerProperties properties) {this.properties = properties.getServlet().getEncoding();}@Bean@ConditionalOnMissingBeanpublic CharacterEncodingFilter characterEncodingFilter() {CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();filter.setEncoding(this.properties.getCharset().name());filter.setForceRequestEncoding(this.properties.shouldForce(org.springframework.boot.web.servlet.server.Encoding.Type.REQUEST));filter.setForceResponseEncoding(this.properties.shouldForce(org.springframework.boot.web.servlet.server.Encoding.Type.RESPONSE));return filter;}}

    從@EnableConfigurationProperties({ServerProperties.class})可知,該類已經(jīng)與配置文件綁定了,所以,如果你改變filter.setEncoding(this.properties.getCharset().name());只需要溯源改變server.servlet.encoding.charset的值就可以了

  • 總結(jié):
  • ? SpringBoot先加載所有的自動配置類 xxxxxAutoConfiguration
    ? 每個自動配置類按照條件進(jìn)行生效,默認(rèn)都會綁定配置文件指定的值。xxxxProperties里面拿。 xxxProperties和配置文件進(jìn)行了綁定
    ? 生效的配置類就會給容器中裝配很多組件
    ? 只要容器中有這些組件,相當(dāng)于這些功能就有了
    ? 定制化配置
    ? 用戶直接自己@Bean替換底層的組件
    ? 用戶去看這個組件是獲取的配置文件什么值就去修改。
    xxxxxAutoConfiguration —> 加載組件 —> xxxxProperties里面拿值 ----> application.properties

    參考文章

    總結(jié)

    以上是生活随笔為你收集整理的SpringBoot(2.4.0)自动配置原理(源码)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。