国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Spring Boot 啟動注解分析

這篇具有很好參考價值的文章主要介紹了Spring Boot 啟動注解分析。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報違法"按鈕提交疑問。

雖然我們在日常開發(fā)中,Spring Boot 使用非常多,算是目前 Java 開發(fā)領(lǐng)域一個標(biāo)配了,但是小伙伴們仔細(xì)想想自己的面試經(jīng)歷,和 Spring Boot 相關(guān)的面試題都有哪些?個人感覺應(yīng)該是比較少的,Spring Boot 本質(zhì)上還是曾經(jīng) SSM 那一套,只是通過各種 starter 簡化了配置而已,其他都是一模一樣的,所以 Spring Boot 中很多面試題還是得回歸到 Spring 中去解答!當(dāng)然這并不是說 Spring Boot 中沒什么可問的,Spring Boot 中其實也有一個非常經(jīng)典的面試題,那就是 Spring Boot 中的自動化配置是怎么實現(xiàn)的?今天就來和各位小伙伴聊一下這個問題。

其實之前和小伙伴們聊過相關(guān)的問題,不過都是零散的,沒有系統(tǒng)梳理過,之前也帶領(lǐng)小伙伴們自定義過一個 starter,相信各位小伙伴對于 starter 的原理也有一定了解,所以今天這篇文章一些過于細(xì)節(jié)的內(nèi)容我就不贅述了,大家可以翻看之前的文章。

1. @SpringBootApplication

要說 Spring Boot 的自動化配置,那必須從項目的啟動類 @SpringBootApplication 說起,這是整個 Spring Boot 宇宙的起點(diǎn),我們先來看下這個注解:

@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 {

}

可以看到,@SpringBootApplication 注解組合了多個常見注解的功能,其中:

  • 前四個是元注解,這里我們不做討論。
  • 第五個 @SpringBootConfiguration 是一個支持配置類的注解,這里我們也不做討論。
  • 第六個 @EnableAutoConfiguration 這個注解就表示開啟自動化配置,這是我們今天要聊得重點(diǎn)。
  • 第七個 @ComponentScan 是一個包掃描注解,為什么 Spring Boot 項目中的 Bean 只要放對位置就會被自動掃描到,和這個注解有關(guān)。

別看這里注解多,其實真正由 Spring Boot 提供的注解一共就兩個,分別是 @SpringBootConfiguration@EnableAutoConfiguration 兩個,其他注解在 Spring Boot 出現(xiàn)之前就已經(jīng)存在多年了。

2. @EnableAutoConfiguration

接下來我們來看看 @EnableAutoConfiguration 是如何實現(xiàn)自動化配置的。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

}

這個注解起關(guān)鍵作用的就是兩個東西:

  1. @AutoConfigurationPackage:這個表示自動掃描各種第三方的注解,在之前的文章中已經(jīng)和大家聊過這個注解的作用了,傳送門:@AutoConfigurationPackage 和 @ComponentScan 有何區(qū)別?
  2. @Import 則是在導(dǎo)入 AutoConfigurationImportSelector 配置類,這個配置類里邊就是去加載各種自動化配置類的。

3. AutoConfigurationImportSelector

AutoConfigurationImportSelector 類中的方法比較多,入口的地方則是 process 方法,所以我們這里就從 process 方法開始看起:

@Override
public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
 Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector,
   () -> String.format("Only %s implementations are supported, got %s",
     AutoConfigurationImportSelector.class.getSimpleName(),
     deferredImportSelector.getClass().getName()));
 AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
  .getAutoConfigurationEntry(annotationMetadata);
 this.autoConfigurationEntries.add(autoConfigurationEntry);
 for (String importClassName : autoConfigurationEntry.getConfigurations()) {
  this.entries.putIfAbsent(importClassName, annotationMetadata);
 }
}

從類名就可以看出來,跟自動化配置相關(guān)的對象是由 AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector).getAutoConfigurationEntry(annotationMetadata); 進(jìn)行加載的。

當(dāng)然這里的 getAutoConfigurationEntry 方法實際上就是當(dāng)前類提供的方法,我們來看下該方法:

protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
 if (!isEnabled(annotationMetadata)) {
  return EMPTY_ENTRY;
 }
 AnnotationAttributes attributes = getAttributes(annotationMetadata);
 List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
 configurations = removeDuplicates(configurations);
 Set<String> exclusions = getExclusions(annotationMetadata, attributes);
 checkExcludedClasses(configurations, exclusions);
 configurations.removeAll(exclusions);
 configurations = getConfigurationClassFilter().filter(configurations);
 fireAutoConfigurationImportEvents(configurations, exclusions);
 return new AutoConfigurationEntry(configurations, exclusions);
}

這里源碼的方法命名都做的不錯,基本上都能做到見名知意,小伙伴們?nèi)粘i_發(fā)中,應(yīng)該向這樣的命名思路看齊。接下來我們就來挨個看一下這里的關(guān)鍵方法。

3.1 isEnabled

首先調(diào)用 isEnabled 方法去判斷自動化配置到底有沒有開啟,這個主要是因為我們及時在項目中引入了 spring-boot-starter-xxx 之后,我們也可以通過在 application.properties 中配置 spring.boot.enableautoconfiguration=false 來關(guān)閉所有的自動化配置。

相關(guān)源碼如下:

protected boolean isEnabled(AnnotationMetadata metadata) {
 if (getClass() == AutoConfigurationImportSelector.class) {
  return getEnvironment().getProperty(EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY, Boolean.class, true);
 }
 return true;
}

3.2 getCandidateConfigurations

接下來調(diào)用 getCandidateConfigurations 方法去獲取所有候選的自動化配置類,這些候選的自動化配置類主要來自兩個地方:

  1. 在之前的自定義 starter 中和大家聊過,我們需要在 claspath\:META-INF/spring.factories 中定義出來所有的自動化配置類,這是來源一。
  2. Spring Boot 自帶的自動化配置類,這個在之前的 vhr 視頻中也和小伙伴們多次講過,Spring Boot 自帶的自動化配置類位于 spring-boot-autoconfigure-3.0.6.jar!\META-INF\spring\org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件中。

相關(guān)源碼如下:

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
 List<String> configurations = new ArrayList<>(
   SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()));
 ImportCandidates.load(AutoConfiguration.class, getBeanClassLoader()).forEach(configurations::add);
 Assert.notEmpty(configurations,
   "No auto configuration classes found in META-INF/spring.factories nor in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you "
     + "are using a custom packaging, make sure that file is correct.");
 return configurations;
}

這里加載到的自動化配置類的全路徑被存入到 configurations 對象中,該對象有兩個獲取的地方:

  1. 調(diào)用 SpringFactoriesLoader.loadFactoryNames 方法獲取,這個方法細(xì)節(jié)我就不帶大家看了,比較簡單,本質(zhì)上就是去加載 META-INF/spring.factories 文件,這個文件中定義了大量的自動化配置類的全路徑。
  2. 調(diào)用 ImportCandidates.load 方法去加載,這個就是加載 spring-boot-autoconfigure-3.0.6.jar!\META-INF\spring\org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件中的自動化配置類。

如果這兩個地方都沒有加載到任何自動化配置類,那么就會拋出一個異常。

3.3 removeDuplicates

removeDuplicates 方法表示移除候選自動化配置類中重復(fù)的類,移除的思路也很有意思,就用一個 LinkedHashSet 中轉(zhuǎn)一下就行了,源碼如下:

protected final <T> List<T> removeDuplicates(List<T> list) {
 return new ArrayList<>(new LinkedHashSet<>(list));
}

可以看到這些源碼里有時候一些解決思路也很有意思。

3.4 getExclusions

getExclusions 方法表示需要獲取到所有被排除的自動化配置類,這些被排除的自動化配置類可以從三個地方獲?。?/p>

  1. 當(dāng)前注解的 exclude 屬性。
  2. 當(dāng)前注解的 excludeName 屬性。
  3. application.properties 配置文件中的 spring.autoconfigure.exclude 屬性。

來看一下相關(guān)源碼:

protected Set<String> getExclusions(AnnotationMetadata metadata, AnnotationAttributes attributes) {
 Set<String> excluded = new LinkedHashSet<>();
 excluded.addAll(asList(attributes, "exclude"));
 excluded.addAll(asList(attributes, "excludeName"));
 excluded.addAll(getExcludeAutoConfigurationsProperty());
 return excluded;
}

跟上面講解的三點(diǎn)剛好對應(yīng)。

3.5 checkExcludedClasses

這個方法是檢查所有被排除的自動化配置類,由于 Spring Boot 中的自動化配置類可以自定義,并不需要統(tǒng)一實現(xiàn)某一個接口或者統(tǒng)一繼承某一個類,所以在寫排除類的時候,如果寫錯了編譯是校驗不出來的,像下面這種:

@SpringBootApplication(exclude = HelloController.class)
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }
}

由于 HelloController 并不是一個自動化配置類,所以這樣寫項目啟動的時候就會報錯,如下:

Spring Boot 啟動注解分析,spring boot,spring boot,java,數(shù)據(jù)庫

這個異常從哪來的呢?其實就是來自 checkExcludedClasses 方法,我們來看下該方法:

private void checkExcludedClasses(List<String> configurations, Set<String> exclusions) {
 List<String> invalidExcludes = new ArrayList<>(exclusions.size());
 for (String exclusion : exclusions) {
  if (ClassUtils.isPresent(exclusion, getClass().getClassLoader()) && !configurations.contains(exclusion)) {
   invalidExcludes.add(exclusion);
  }
 }
 if (!invalidExcludes.isEmpty()) {
  handleInvalidExcludes(invalidExcludes);
 }
}
protected void handleInvalidExcludes(List<String> invalidExcludes) {
 StringBuilder message = new StringBuilder();
 for (String exclude : invalidExcludes) {
  message.append("\t- ").append(exclude).append(String.format("%n"));
 }
 throw new IllegalStateException(String.format(
   "The following classes could not be excluded because they are not auto-configuration classes:%n%s",
   message));
}

可以看到,在 checkExcludedClasses 方法中,會首先找到所有位于當(dāng)前類路徑下但是卻不包含在 configurations 中的所有被排除的自動化配置類,由于 configurations 中的就是所有的自動化配置類了,所以這些不存在于 configurations 中的類都是有問題的,都不是自動化配置類,將這些有問題的類收集起來,存入到 invalidExcludes 變量中,然后再進(jìn)行額外的處理。

所謂額外的處理就是在 handleInvalidExcludes 方法中拋出異常,前面截圖中的異常就是來自這里。

3.6 removeAll

這個方法就一個任務(wù),就是從 configurations 中移除掉那些被排除的自動化配置類。configurations 本身就是 List 集合,exclusions 則是一個 Set 集合,所以這里直接移除即可。

3.7 filter

現(xiàn)在我們已經(jīng)加載了所有的自動化配置類了,但是這些配置類并不是都會生效,具體是否生效,還要看你的項目是否使用了具體的依賴。

例如,現(xiàn)在加載的自動化配置里里邊就包含了 RedisAutoConfiguration,這個是自動配置 Redis 的,但是由于我的項目中并沒有使用 Redis,所以這個自動化配置類并不會生效。這個過程就是由 getConfigurationClassFilter().filter(configurations); 來完成的。

先說一個預(yù)備知識:

由于我們項目中的自動化配置類特別多,每一個自動化配置類都會依賴別的類,當(dāng)別的類存在時,這個自動化配置類才會生效,這一堆互相之間的依賴關(guān)系,存在于 spring-boot-autoconfigure-3.0.6.jar!/META-INF/spring-autoconfigure-metadata.properties 文件之中,我隨便舉一個該文件中的配置:

  • org.springframework.boot.autoconfigure.amqp.RabbitAnnotationDrivenConfiguration.ConditionalOnClass=org.springframework.amqp.rabbit.annotation.EnableRabbit 表示 RabbitAnnotationDrivenConfiguration 類要生效有一個必備條件就是當(dāng)前項目類路徑下要存在 org.springframework.amqp.rabbit.annotation.EnableRabbit。

我們來看看 RabbitAnnotationDrivenConfiguration 類的注解:

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(EnableRabbit.class)
class RabbitAnnotationDrivenConfiguration {
}

這個類和配置文件中的內(nèi)容一致。

這個預(yù)備知識搞懂了,接下來的內(nèi)容就好理解了。

先來看 getConfigurationClassFilter 方法,這個就是獲取所有的過濾器,如下:

private ConfigurationClassFilter getConfigurationClassFilter() {
 if (this.configurationClassFilter == null) {
  List<AutoConfigurationImportFilter> filters = getAutoConfigurationImportFilters();
  for (AutoConfigurationImportFilter filter : filters) {
   invokeAwareMethods(filter);
  }
  this.configurationClassFilter = new ConfigurationClassFilter(this.beanClassLoader, filters);
 }
 return this.configurationClassFilter;
}

可以看到,這里獲取到的過濾器都是 AutoConfigurationImportFilter 類型的,這個類型的過濾器只有三個實例,如下圖:

Spring Boot 啟動注解分析,spring boot,spring boot,java,數(shù)據(jù)庫

從這三個實例的名字中,基本上就能看出來各自的作用:

  • OnClassCondition:這個就是條件注解 @ConditionalOnClass 的判定條件,看名字就知道用來判斷當(dāng)前 classpath 下是否存在某個類。
  • OnWebApplicationCondition:這個是條件注解 ConditionalOnWebApplication 的判定條件,用來判斷當(dāng)前系統(tǒng)環(huán)境是否是一個 Web 環(huán)境。
  • OnBeanCondition:這個是條件注解 @ConditionalOnBean 的判定條件,就是判斷當(dāng)前系統(tǒng)下是否存在某個 Bean。

這里獲取到的三個 AutoConfigurationImportFilter 過濾器其實就是上面這三個。接下來執(zhí)行 filter 方法,如下:

List<String> filter(List<String> configurations) {
 long startTime = System.nanoTime();
 String[] candidates = StringUtils.toStringArray(configurations);
 boolean skipped = false;
 for (AutoConfigurationImportFilter filter : this.filters) {
  boolean[] match = filter.match(candidates, this.autoConfigurationMetadata);
  for (int i = 0; i < match.length; i++) {
   if (!match[i]) {
    candidates[i] = null;
    skipped = true;
   }
  }
 }
 if (!skipped) {
  return configurations;
 }
 List<String> result = new ArrayList<>(candidates.length);
 for (String candidate : candidates) {
  if (candidate != null) {
   result.add(candidate);
  }
 }
 return result;
}

這里就是遍歷這三個過濾器,然后分別調(diào)用各自的 match 方法和 144 個自動化配置類進(jìn)行匹配,如果這些自動化配置類所需要的條件得到滿足,則 match 數(shù)組對應(yīng)的位置就為 true,否則就為 false。

然后遍歷 match 數(shù)組,將不滿足條件的自動化配置類置為 null,最后再把這些 null 移除掉。

這樣就獲取到了我們需要進(jìn)行自動化配置的類了。

最后一句 fireAutoConfigurationImportEvents 則是觸發(fā)自動化配置類導(dǎo)入事件,這個沒啥好說的~

當(dāng)這些自動化配置類加載進(jìn)來之后,接下來就是各種條件注解來決定這些配置類是否生效了,這些都比較簡單了,之前在 vhr 種也和小伙伴們講過多次了,這里就不再啰嗦了~

好啦,經(jīng)過上面的梳理相信小伙伴們對 Spring Boot 自動化配置類的加載有一個大概的認(rèn)知了吧~文章來源地址http://www.zghlxwxcb.cn/news/detail-641336.html

到了這里,關(guān)于Spring Boot 啟動注解分析的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點(diǎn)擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Spring Boot啟動源碼分析

    Spring Boot啟動源碼分析

    版本:spring-boot-starter-parent版本為2.3.0 Spring Boot項目的啟動入口是一個main方法,因此我們從該方法入手即可 跟蹤run方法 這里分兩步debug: new SpringApplication( primarySources ) 執(zhí)行run()方法 deduceFromClasspath推斷應(yīng)用程序類型 該方法根據(jù)是否存在指定路徑的類來推斷應(yīng)用程序類型。有

    2024年02月07日
    瀏覽(20)
  • java spring boot 注解、接口和問題解決方法(持續(xù)更新)

    java spring boot 注解、接口和問題解決方法(持續(xù)更新)

    @RestController ????????是SpringMVC框架中的一個注解,它結(jié)合了@Controller和@ResponseBody兩個注解的功能,用于標(biāo)記一個類或者方法,表示該類或方法用于處理HTTP請求,并將響應(yīng)的結(jié)果直接返回給客戶端,而不需要進(jìn)行視圖渲染 @Controller ????????是Spring Framework中的注解,用于

    2024年02月06日
    瀏覽(31)
  • Spring Boot實現(xiàn)第一次啟動時自動初始化數(shù)據(jù)庫

    Spring Boot實現(xiàn)第一次啟動時自動初始化數(shù)據(jù)庫

    在現(xiàn)在的后端開發(fā)中,只要是運(yùn)用聯(lián)系型數(shù)據(jù)庫,信任SSM架構(gòu)(Spring Boot + MyBatis)已經(jīng)成為首選。 不過在咱們第一次運(yùn)轉(zhuǎn)或許布置項目的時分,一般要先手動銜接數(shù)據(jù)庫,履行一個SQL文件以創(chuàng)立數(shù)據(jù)庫以及數(shù)據(jù)庫表格完結(jié) 數(shù)據(jù)庫的初始化作業(yè) ,這樣咱們的SSM應(yīng)用程序才能夠

    2024年02月03日
    瀏覽(24)
  • spring boot 啟動報錯---java: 無法訪問org.springframework.boot.SpringApplication 錯誤的類文件:

    spring boot 啟動報錯---java: 無法訪問org.springframework.boot.SpringApplication 錯誤的類文件:

    目錄 錯誤提示信息: 原因: 解決辦法: 具體步驟: 主要是因為 spring boot 3.0發(fā)布了 ,在創(chuàng)建項目時,默認(rèn)為3.0 ` 但同時, spring boot 3.0 只支持jdk 17 ,在平時創(chuàng)建時,都喜歡使用jdk8 由于 spring boot 版本默認(rèn)3.0,同時jdk選擇的是 8 ,就會導(dǎo)致這個錯誤 將 spring boot 版本和jdk統(tǒng)一

    2024年02月15日
    瀏覽(16)
  • Spring Boot常用注解

    在 Spring Boot 中,有許多注解用于簡化和標(biāo)識應(yīng)用程序的不同方面。以下是一些常用的 Spring Boot 注解: @SpringBootApplication : 用于標(biāo)識主應(yīng)用程序類。通常與 @EnableAutoConfiguration 、 @ComponentScan 和 @Configuration 一起使用,它是一個復(fù)合注解,用于簡化配置。 @Controller : 用于標(biāo)識控

    2024年01月19日
    瀏覽(35)
  • Spring boot注解講解

    Spring boot注解講解

    人不走空 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? ? ? 目錄 ? ????????個人主頁:人不走空?????? ??系列專欄:算法專題 ?詩詞歌賦:斯是陋室,惟吾德馨 ? 注解 注解列表如下 JPA注解 作者其他作品: ? @SpringBootApplication :申

    2024年02月19日
    瀏覽(23)
  • Spring boot 常見注解

    Spring Boot是一個基于Spring框架的快速開發(fā)框架,它通過自動化配置和約定優(yōu)于配置的原則,簡化了Spring應(yīng)用程序的開發(fā)過程。Spring Boot可以幫助開發(fā)者快速構(gòu)建獨(dú)立的、生產(chǎn)級別的應(yīng)用程序,并且可以與其他Spring框架和第三方庫無縫集成。 Spring Boot提供了很多便利的特性,比如

    2024年01月18日
    瀏覽(20)
  • Java(一):創(chuàng)建 Spring Boot 項目并實現(xiàn)連接操作MySQL數(shù)據(jù)庫

    Java(一):創(chuàng)建 Spring Boot 項目并實現(xiàn)連接操作MySQL數(shù)據(jù)庫

    MySQL 命令 Maven 相關(guān)地址 下載地址: https://maven.apache.org/ maven配置方法地址: https://developer.aliyun.com/mvn/guide 倉庫搜索地址: https://mvnrepository.com/ https://repo.maven.apache.org/ maven 本地配置 conf/settings.xml 下載 idea 并配置本地環(huán)境 maven Maven 構(gòu)建 生命周期 Maven 的構(gòu)建 生命周期 包括 三

    2024年02月07日
    瀏覽(28)
  • Spring boot自定義注解

    定義一個注解類 使用AOP對注解進(jìn)行解析,需要定義一個切面類,包括自定義的切點(diǎn)方法normalPointCut(),以及連接點(diǎn)的處理方法normalPointAround()。連接點(diǎn)中的ProceedingJoinPoint可以獲取被代理類的方法屬性等。 2.1 定義注解 2.2 實現(xiàn)參數(shù)解釋器 記得實現(xiàn)WebMvcConfigurer 接口配置LimitReque

    2023年04月27日
    瀏覽(27)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包