最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot自動配置源碼深入刨析講解

 更新時間:2022年09月08日 15:56:28   作者:天黑請閉眼丶風  
這篇文章主要介紹了SpringBoot自動配置原理分析,SpringBoot是我們經常使用的框架,那么你能不能針對SpringBoot實現自動配置做一個詳細的介紹。如果可以的話,能不能畫一下實現自動配置的流程圖。牽扯到哪些關鍵類,以及哪些關鍵點

自動配置底層源碼分析

本次springboot源碼來自2.6.6版本。

@EnableAutoConfiguration源碼解析

在springboot中,當我們引入某個依賴,就可以直接使用依賴里面的類進行自動注入,不需要像ssm框架那樣在xml文件中配置各種bean,然后進行關聯。像這樣我們稱之為自動配置。那么自動配置到底配了什么?

SpringBoot中的自動配置,更多的是配置各種Bean,同時對于端口號這些配置,一些特定屬性SpringBoot也是會提供一種默認值的,也相當于一種自動配置。

那SpringBoot是如何自動的幫助我們來配置這些Bean的呢?并且如果某些Bean程序員自己也配置了,那SpringBoot是如何進行選擇的呢?

在springboot啟動類中有@SpringBootApplication注解,該注解包含了@EnableAutoConfiguration

而@EnableAutoConfiguration的作用就是導入AutoConfigurationImportSelector.class這個類。在spring中的配置類源碼分析中,分析過@Import導入的類會當成配置類來解析,并且如果這個配置類是實現了DeferredImportSelector接口,就會調用selectImports方法。這部分屬于spring源碼的知識不在贅述。

有上述類關系圖中可以看出,會調用AutoConfigurationImportSelector的selectImports方法

@Override
	public String[] selectImports(AnnotationMetadata annotationMetadata) {
		// 會在所有@Configuration都解析完了之后才執(zhí)行
		if (!isEnabled(annotationMetadata)) {
			return NO_IMPORTS;
		}
		// 獲取自動配置類(spring.factories中所導入的)
		AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
		return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
	}

而selectImports的核心代碼在于getAutoConfigurationEntry(annotationMetadata)。接下來一步步分析這個方法

protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return EMPTY_ENTRY;
		}
		// 獲取@EnableAutoConfiguration的屬性
		AnnotationAttributes attributes = getAttributes(annotationMetadata);
		// 獲取spring.factories中所有的AutoConfiguration
		List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
		// 去重(也就是按類名去重)
		configurations = removeDuplicates(configurations);
		// 獲取需要排除的AutoConfiguration,可以通過@EnableAutoConfiguration注解的exclude屬性,或者spring.autoconfigure.exclude來配置
		Set<String> exclusions = getExclusions(annotationMetadata, attributes);
		// 排除
		checkExcludedClasses(configurations, exclusions);
		configurations.removeAll(exclusions);
		// 獲取spring.factories中的AutoConfigurationImportFilter對AutoConfiguration進行過濾
		// 默認會拿到OnBeanCondition、OnClassCondition、OnWebApplicationCondition
		// 這三個會去判斷上面的AutoConfiguration是否符合它們自身所要求的條件,不符合的會過濾掉,表示不會進行解析了
		// 會利用spring-autoconfigure-metadata.properties中的配置來進行過濾
		// spring-autoconfigure-metadata.properties文件中的內容是利用Java中的AbstractProcessor技術在編譯時生成出來的
		configurations = getConfigurationClassFilter().filter(configurations);
		// configurations表示合格的,exclusions表示被排除的,把它們記錄在ConditionEvaluationReportAutoConfigurationImportListener中
		fireAutoConfigurationImportEvents(configurations, exclusions);

		// 最后返回的AutoConfiguration都是符合條件的
		return new AutoConfigurationEntry(configurations, exclusions);
	}

首先執(zhí)行 AnnotationAttributes attributes = getAttributes(annotationMetadata);拿到@EnableAutoConfiguration的屬性封裝成AnnotationAttributes 。List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes)加載自動配置類??纯丛创a是怎么獲取的

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
		//核心方法 傳入EnableAutoConfiguration類和類加載器
		List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
				getBeanClassLoader());
		Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
				+ "are using a custom packaging, make sure that file is correct.");
		return configurations;
	}
//返回EnableAutoConfiguration
protected Class<?> getSpringFactoriesLoaderFactoryClass() {
		return EnableAutoConfiguration.class;
	}
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
		ClassLoader classLoaderToUse = classLoader;
		if (classLoaderToUse == null) {
			//獲取類加載器
			classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
		}
		//這個name就是EnableAutoConfiguration
		String factoryTypeName = factoryType.getName();
		//這部分代碼具體的去加載自動配置類
		return loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
	}

loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());這部分代碼如下圖,

通過類加載去加載資源,其中紅色部分的靜態(tài)變量就是 public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";。也就是說類加載器去META-INF/spring.factories里面的資源

.getOrDefault(factoryTypeName, Collections.emptyList());這部分就是根據factoryTypeName也就是EnableAutoConfiguration。獲取EnableAutoConfiguration的值封裝成List<String>

到此就獲取到了所有自動配置類。那么List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);這個方法就結束了。接著執(zhí)行configurations = removeDuplicates(configurations);這部分主要用去重

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

接著執(zhí)行Set<String> exclusions = getExclusions(annotationMetadata, attributes);這個方法主要是把需要排除的配置類的類名放入到集合當中。

protected Set<String> getExclusions(AnnotationMetadata metadata, AnnotationAttributes attributes) {
		Set<String> excluded = new LinkedHashSet<>();
		//獲取EnableAutoConfiguration注解的exclude屬性的值 添加到排除集合當中
		excluded.addAll(asList(attributes, "exclude"));
		//獲取EnableAutoConfiguration注解的excludeName屬性的值 添加到排除集合當中
		excluded.addAll(Arrays.asList(attributes.getStringArray("excludeName")));
		//從配置文件中獲取spring.autoconfigure.exclude 的值 添加到排除集合中
		excluded.addAll(getExcludeAutoConfigurationsProperty());
		return excluded;
	}

往下執(zhí)行checkExcludedClasses(configurations, exclusions);configurations.removeAll(exclusions); 從之前獲取到的自動配置類的類名中排除掉那些需要被排除了類名。

接著執(zhí)行configurations = getConfigurationClassFilter().filter(configurations);。將排除后的自動配置類的名稱作為入參,這部分代碼是提前判斷一些條件進行過濾掉不需要加載的自動配置類

private ConfigurationClassFilter getConfigurationClassFilter() {
		if (this.configurationClassFilter == null) {
			//獲取自動配置類的過濾器
			List<AutoConfigurationImportFilter> filters = getAutoConfigurationImportFilters();
			for (AutoConfigurationImportFilter filter : filters) {
				invokeAwareMethods(filter);
			}
			//將所有過濾器封裝成 ConfigurationClassFilter
			this.configurationClassFilter = new ConfigurationClassFilter(this.beanClassLoader, filters);
		}
		return this.configurationClassFilter;
	}
protected List<AutoConfigurationImportFilter> getAutoConfigurationImportFilters() {
		//底層從 META-INF/spring.factories中加載 AutoConfigurationImportFilter的值
		return SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class, this.beanClassLoader);
	}

上面獲取到的過濾器就是這部分

獲取到所有過濾器后通過filter(configurations);進行過濾

List<String> filter(List<String> configurations) {
			long startTime = System.nanoTime();
			//把自動配置類的名稱封裝成數組
			String[] candidates = StringUtils.toStringArray(configurations);
			boolean skipped = false;
			// 逐個利用AutoConfigurationImportFilter來判斷所有的自動配置類的條件是否匹配,匹配結果存在match數組中
			// 先利用OnBeanCondition進行過濾
			// 再利用OnClassCondition進行過濾
			// 再利用OnWebApplicationCondition進行過濾
			for (AutoConfigurationImportFilter filter : this.filters) {
				//把過濾的結果 放入到boolean的數組中
				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;
			}
			// 把匹配的記錄在result集合中,最后返回
			List<String> result = new ArrayList<>(candidates.length);
			for (String candidate : candidates) {
				if (candidate != null) {
					result.add(candidate);
				}
			}
			if (logger.isTraceEnabled()) {
				int numberFiltered = configurations.size() - result.size();
				logger.trace("Filtered " + numberFiltered + " auto configuration class in "
						+ TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime) + " ms");
			}
			return result;
		}
	}

過濾完成后執(zhí)行fireAutoConfigurationImportEvents(configurations, exclusions); 這部分不重要 ,可以看成就是記錄一個日志,哪些成功的哪些被排除的。

最后執(zhí)行return new AutoConfigurationEntry(configurations, exclusions); 這部分代碼把 可以加載的自動配置類 放入到一個集合,把排除的放入到另一個集合

AutoConfigurationEntry(Collection<String> configurations, Collection<String> exclusions) {
			this.configurations = new ArrayList<>(configurations);
			this.exclusions = new HashSet<>(exclusions);
		}
		public List<String> getConfigurations() {
			return this.configurations;
		}
		public Set<String> getExclusions() {
			return this.exclusions;
		}

到此所有需要加載的自動配置類都找到了。然后再回到一開始的selectImports方法這個方法最后返回StringUtils.toStringArray(autoConfigurationEntry.getConfigurations())。返回所有符合自動配置類的全類名。根據@Import功能會繼續(xù)將selectImports返回的類名,當成配置類去加載。那么每個自動配置類就會加載到springboot當中。

到此springboot自動配置功能就結束了。至于加載自動配置類加載過程中,根據條件注解去匹配是否能夠加載,下一篇在分析。

總結

springboot啟動類中存在@SpringBootApplication,而@SpringBootApplication中包含@EnableAutoConfiguration。@EnableAutoConfiguration中通過@Import引入AutoConfigurationImportSelector。

spring啟動的時候調用AutoConfigurationImportSelector的selectImports。該方法獲取到所有可以加載的自動配置類(此時還未加載)

獲取過程如下:

  1. 獲取@EnableAutoConfiguration的屬性的值封裝成AnnotationAttributes
  2. 獲取spring.factories中key為EnableAutoConfiguration的值作為自動配置類的名稱
  3. 將獲取到的所有的自動配置類的名稱進行去重
  4. 獲取程序員配置的需要排除的自動配置類,從上一步找到的所有自動配置類中排除掉
  5. 獲取spring.factories中key為AutoConfigurationImportFilter的值作為過濾器封裝成ConfigurationClassFilter
  6. 通過ConfigurationClassFilter初次過濾不滿足條件的自動配置類
  7. 把排除的自動配置類和最終可加載的自動配置類進行日志記錄
  8. 把排除的自動配置類和最終可加載的自動配置類分別放入到集合當中,封裝成AutoConfigurationEntry返回

最后selectImports從AutoConfigurationEntry拿出可加載的自動配置類的名稱返回。這樣springboot就會去加載那些配置類

到此這篇關于SpringBoot自動配置源碼深入刨析講解的文章就介紹到這了,更多相關SpringBoot自動配置內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • MyBatis中${}?和?#{}?有什么區(qū)別小結

    MyBatis中${}?和?#{}?有什么區(qū)別小結

    ${}?和?#{}?都是?MyBatis?中用來替換參數的,它們都可以將用戶傳遞過來的參數,替換到?MyBatis?最終生成的?SQL?中,但它們區(qū)別卻是很大的,今天通過本文介紹下MyBatis中${}?和?#{}?有什么區(qū)別,感興趣的朋友跟隨小編一起看看吧
    2022-11-11
  • springboot + mybatis + druid + 多數據源的問題詳解

    springboot + mybatis + druid + 多數據源的問題詳解

    這篇文章主要介紹了springboot + mybatis + druid + 多數據源的問題詳解,示例代碼文字相結合給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-09-09
  • Spring中的模塊與應用場景詳解

    Spring中的模塊與應用場景詳解

    這篇文章主要介紹了Spring中的模塊與應用場景詳解,Spring 框架可以為 Java 應用程序開發(fā)提供全面的基礎設施支持,它是現在非常流行的 Java 開源框架,對于一個 Java 開發(fā)人員來說,熟練掌握 Spring 是必不可少的,需要的朋友可以參考下
    2023-09-09
  • spring cloud 分布式鏈路追蹤的方法

    spring cloud 分布式鏈路追蹤的方法

    這篇文章主要介紹了spring cloud 分布式鏈路追蹤的方法,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-07-07
  • Java圖形界面框架AWT布局管理器詳解

    Java圖形界面框架AWT布局管理器詳解

    這篇文章主要介紹了Java圖形界面框架AWT布局管理器,AWT是最早的圖形用戶界面框架之一,它為開發(fā)人員提供了一些基本的組件和工具,用于構建窗口、按鈕、文本框、標簽等圖形界面元素,需要的朋友可以參考下
    2025-04-04
  • 使用MyEclipse 開發(fā)struts2框架實現登錄功能(結構教程)

    使用MyEclipse 開發(fā)struts2框架實現登錄功能(結構教程)

    這篇文章主要介紹了使用MyEclipse 開發(fā)struts2框架實現登錄功能(結構教程)的相關資料,需要的朋友可以參考下
    2016-03-03
  • JavaCV實現人臉檢測功能

    JavaCV實現人臉檢測功能

    這篇文章主要為大家詳細介紹了JavaCV實現人臉檢測功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-02-02
  • Java并發(fā)編程ArrayBlockingQueue的使用

    Java并發(fā)編程ArrayBlockingQueue的使用

    ArrayBlockingQueue是一個備受矚目的有界阻塞隊列,本文將全面深入地介紹ArrayBlockingQueue的內部機制、使用場景以及最佳實踐,感興趣的可以了解一下
    2024-08-08
  • 深入理解Spring中的循環(huán)依賴

    深入理解Spring中的循環(huán)依賴

    Spring在注入bean的時候會做循環(huán)依賴檢查,下面這篇文章主要給大家介紹了關于Spring中循環(huán)依賴的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面來一起看看吧
    2018-05-05
  • 基于SpringBoot實現大文件分塊上傳功能

    基于SpringBoot實現大文件分塊上傳功能

    這篇文章主要介紹了基于SpringBoot實現大文件分塊上傳功能,實現原理其實很簡單,核心就是客戶端把大文件按照一定規(guī)則進行拆分,比如20MB為一個小塊,分解成一個一個的文件塊,然后把這些文件塊單獨上傳到服務端,需要的朋友可以參考下
    2024-09-09

最新評論

河曲县| 南岸区| 集安市| 桐乡市| 年辖:市辖区| 玉环县| 阿克陶县| 宜良县| 温宿县| 略阳县| 大埔区| 喀什市| 新津县| 汕头市| 玉山县| 盐边县| 湘乡市| 永寿县| 习水县| 台东市| 通海县| 淳化县| 京山县| 长寿区| 剑阁县| 长丰县| 上饶县| 博罗县| 霍林郭勒市| 纳雍县| 濉溪县| 苗栗县| 枣强县| 平遥县| 兴和县| 攀枝花市| 长岛县| 叶城县| 福安市| 汤原县| 阜宁县|