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

SpringBoot自動(dòng)裝配原理詳解

 更新時(shí)間:2021年03月09日 09:22:28   作者:Java伴我余生  
這篇文章主要介紹了SpringBoot自動(dòng)裝配原理的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)使用SpringBoot框架,感興趣的朋友可以了解下

首先對(duì)于一個(gè)SpringBoot工程來說,最明顯的標(biāo)志的就是 @SpringBootApplication它標(biāo)記了這是一個(gè)SpringBoot工程,所以今天的 SpringBoot自動(dòng)裝配原理也就是從它開始說起。

自動(dòng)裝配流程

首先我們來看下@SpringBootApplication 這個(gè)注解的背后又有什么玄機(jī)呢,我們按下 ctrl + 鼠標(biāo)左鍵,輕輕的點(diǎn)一下,此時(shí)見證奇跡的時(shí)刻..
我們看到如下優(yōu)雅的代碼:

這其中有兩個(gè)比較容易引起我們注意的地方,一個(gè)是@SpringBootConfiguration注解,另一個(gè)是@EnableAutoConfiguration注解;之所以說這個(gè)兩個(gè)注解比較吸引我們的眼球, 不是因?yàn)樗鼈冮L(zhǎng)大的好看,而是因?yàn)槠渌淖⒔馓y看了(主要是因?yàn)槠渌淖⒔馕覀兌际潜容^熟悉,即使不知道他們是干什么的,可以肯定更自動(dòng)裝配是沒有關(guān)系的)。 然后我們又伸出了邪惡的小手,開啟了熟悉的操作,按下了Ctrt + 鼠標(biāo)左鍵,瞪著色咪咪的小眼睛,瞳孔放大了百倍等待著奇跡的出現(xiàn)... 擦... 擦...擦...

什么也沒有...
那我要你有何用,這么頂級(jí)的世界級(jí)的開源項(xiàng)目,怎么會(huì)讓一個(gè)沒用的家伙存在呢? 于是動(dòng)用了上億的腦細(xì)胞大軍,經(jīng)過復(fù)雜的運(yùn)算,得出了一個(gè)不靠譜的結(jié)論:它可能使用來標(biāo)記這是一個(gè)SpringBoot工程的配置。因?yàn)?code>SpringBootConfiguration翻譯過來就是SpringBoot的配置,于是心中又是幾萬只羊駝在萬馬奔騰,大漠飛揚(yáng)。

氣定神閑之后,秉承著·失敗是成功之母"的信念, 熟練的左手行云流水般的按下了 Ctrl + Table 鍵,回到了最初的的地方。眼睛盯著 @EnableAutoConfiguration ,環(huán)顧左右,在地址欄輸入了谷歌翻譯, 結(jié)果顯示 自動(dòng)裝配。我找的就是你,真是眾里尋他千百度,那人卻在燈火闌珊處。 熟練的按下了 Ctrl +左鍵,迫不及待的想要進(jìn)入; 心里默默背誦起了《桃花源記》的經(jīng)典詩句 ∶

林盡水源,便得一山,山有小口,仿佛若有光。便舍船,從口入。初極狹,才通人。復(fù)行數(shù)十步,豁然開朗

此時(shí)此刻心情愉悅,有過前面的經(jīng)歷之后,在面對(duì)新的世界時(shí)候,我們淡定了許多。 此時(shí)大腦高速運(yùn)轉(zhuǎn),沒有再糾結(jié),直搗黃龍,進(jìn)入了 AutoConfigurationImportSelector.class 類,因?yàn)楣雀璺g告訴我們,這個(gè)是自動(dòng)配置導(dǎo)入選擇器。 于是我們發(fā)現(xiàn)了—片新天地

public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
		ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {


	@Override
	public String[] selectImports(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return NO_IMPORTS;
		}
    // 獲取自動(dòng)配置的實(shí)體
		AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
		return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
	}

  // 具體用來加載自動(dòng)配置類得方法
	protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return EMPTY_ENTRY;
		}
		AnnotationAttributes attributes = getAttributes(annotationMetadata);
    // 獲取候選的配置類,即使后宮佳麗三千,也是要篩選的
		List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
    // 根據(jù)情況,自動(dòng)配置需要的配置類和不需要的配置了
		configurations = removeDuplicates(configurations);
		Set<String> exclusions = getExclusions(annotationMetadata, attributes);
		checkExcludedClasses(configurations, );
		configurations.removeAll(exclusions);
		configurations = getConfigurationClassFilter().filter(configurations);
		fireAutoConfigurationImportEvents(configurations, exclusions);
    // 返回最終需要的配置
		return new AutoConfigurationEntry(configurations, exclusions);
	}
}

而這個(gè)自動(dòng)配置的實(shí)體 AutoConfigurationEntry里面有兩個(gè)屬性,configurationsexclusions。

	protected static class AutoConfigurationEntry {
    // 用來存儲(chǔ)需要的配置項(xiàng)
		private final List<String> configurations;
    // 用來存儲(chǔ)排除的配置項(xiàng)
		private final Set<String> exclusions;

		private AutoConfigurationEntry() {
			this.configurations = Collections.emptyList();
			this.exclusions = Collections.emptySet();
		}
  }

在后面可以看到 getAutoConfigurationEntry()方法返回了一個(gè)對(duì)象 return new AutoConfigurationEntry(configurations, exclusions);這里也就是把我們需要的配置都拿到了。

那他是怎么拿到的候選的配置類呢? 我們接著看這個(gè)獲取候選配置類的方法 List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
進(jìn)到方法后我們看到下面這個(gè)方法具體獲取候選配置類的方法內(nèi)容

這里我們跟著斷點(diǎn)去走,首先進(jìn)入getSpringFactoriesLoaderFactoryClass()方法

	protected Class<?> getSpringFactoriesLoaderFactoryClass() {
    // 返回的是EnableAutoConfiguration字節(jié)碼對(duì)象
		return EnableAutoConfiguration.class;
	}

接著我們?cè)谶M(jìn)入getBeanClassLoader()方法,這里就是一個(gè)類加載器

protected ClassLoader getBeanClassLoader() {
		return this.beanClassLoader;
	}

最后我們?cè)谶M(jìn)入loadFactoryNames()方法,這個(gè)方法就是根據(jù)剛才的字節(jié)碼文件和類加載器來找到候選的配置類。傳遞過來的字節(jié)碼

	public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
		ClassLoader classLoaderToUse = classLoader;
		if (classLoaderToUse == null) {
			classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
		}
    // 獲取的EnableAutoConfiguration.class的權(quán)限定名
    //org.springframework.boot.autoconfigure.EnableAutoConfiguration
		String factoryTypeName = factoryType.getName();
		return loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
	}

如下圖:

最后通過loadSpringFactories()來獲取到所有的配置類

	private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
    // 緩存加載的配置類
		Map<String, List<String>> result = cache.get(classLoader);
		if (result != null) {
			return result;
		}
    
		result = new HashMap<>();
		try {
      // 去資源目錄下找
			Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
			while (urls.hasMoreElements()) {
				URL url = urls.nextElement();
				UrlResource resource = new UrlResource(url);
				Properties properties = PropertiesLoaderUtils.loadProperties(resource);
				for (Map.Entry<?, ?> entry : properties.entrySet()) {
					String factoryTypeName = ((String) entry.getKey()).trim();
					String[] factoryImplementationNames =
							StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
					for (String factoryImplementationName : factoryImplementationNames) {
						result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>())
								.add(factoryImplementationName.trim());
					}
				}
			}

			// Replace all lists with unmodifiable lists containing unique elements
			result.replaceAll((factoryType, implementations) -> implementations.stream().distinct()
					.collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)));
      // 加載完成放到緩存中
			cache.put(classLoader, result);
		}
		catch (IOException ex) {
			throw new IllegalArgumentException("Unable to load factories from location [" +
					FACTORIES_RESOURCE_LOCATION + "]", ex);
		}
    // 返回加載到的配置類
		return result;
	}

這里我們要看下怎么從資源目錄下 FACTORIES_RESOURCE_LOCATION 加載的。下面是加載配置文件的路徑:

也就是項(xiàng)目啟動(dòng)的時(shí)候會(huì)去加載所有 META-INF 下的所有的 spring.factories 文件,我們搜一下這個(gè)這個(gè)文件,我搭建的是一個(gè)很簡(jiǎn)單的 SpringBoot 工程,它會(huì)去這幾個(gè) jar 里面找相關(guān)的配置類

但是最后自動(dòng)裝配的類是這個(gè)spring-boot-autoconfigure-2.4.3.RELEASE.jar

而根據(jù)EnabLeAutoConfiguration.class字節(jié)碼加載的配置類就只有這118自動(dòng)配置類

小結(jié)

實(shí)際上SpringBoot的自動(dòng)裝配原理,其實(shí)就是在項(xiàng)目啟動(dòng)的時(shí)候去加載META-INF下的 spring.factories 文件,好像也沒有那么高大上。當(dāng)然在啟動(dòng)的過程中還會(huì)有其他的配置項(xiàng)的加載,這里咱么直說了自動(dòng)裝配的加載過程。希望對(duì)大家可以有所啟發(fā)。

以上就是SpringBoot自動(dòng)裝配原理詳解的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot自動(dòng)裝配原理的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java導(dǎo)出txt文件的方法

    Java導(dǎo)出txt文件的方法

    這篇文章主要介紹了Java導(dǎo)出txt文件的方法,實(shí)例分析了兩種java導(dǎo)出txt文本文件的使用技巧,需要的朋友可以參考下
    2015-05-05
  • java模擬斗地主發(fā)牌功能

    java模擬斗地主發(fā)牌功能

    這篇文章主要為大家詳細(xì)介紹了java模擬斗地主發(fā)牌,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-10-10
  • JavaWeb-WebSocket瀏覽器服務(wù)器雙向通信方式

    JavaWeb-WebSocket瀏覽器服務(wù)器雙向通信方式

    文章介紹了WebSocket協(xié)議的工作原理和應(yīng)用場(chǎng)景,包括與HTTP的對(duì)比,接著,詳細(xì)介紹了如何在Java中使用WebSocket,包括配置類、服務(wù)編寫和前端頁面的實(shí)現(xiàn)
    2025-02-02
  • MyBatis框架關(guān)聯(lián)映射實(shí)例詳解

    MyBatis框架關(guān)聯(lián)映射實(shí)例詳解

    這篇文章主要介紹了MyBatis框架關(guān)聯(lián)映射,關(guān)系映射主要處理復(fù)雜的SQl查詢,如子查詢,多表聯(lián)查等復(fù)雜查詢,應(yīng)用此種需求時(shí)可以考慮使用,需要的朋友可以參考下
    2022-11-11
  • Java日常練習(xí)題,每天進(jìn)步一點(diǎn)點(diǎn)(35)

    Java日常練習(xí)題,每天進(jìn)步一點(diǎn)點(diǎn)(35)

    下面小編就為大家?guī)硪黄狫ava基礎(chǔ)的幾道練習(xí)題(分享)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧,希望可以幫到你
    2021-07-07
  • springboot IDEA啟動(dòng)兩個(gè)端口服務(wù)nginx負(fù)載過程

    springboot IDEA啟動(dòng)兩個(gè)端口服務(wù)nginx負(fù)載過程

    這篇文章主要介紹了springboot IDEA啟動(dòng)兩個(gè)端口服務(wù)nginx負(fù)載過程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-03-03
  • Java基礎(chǔ)之java處理ip的工具類

    Java基礎(chǔ)之java處理ip的工具類

    這篇文章主要介紹了Java基礎(chǔ)應(yīng)用,使用java處理ip的工具類的相關(guān)資料,需要的朋友可以參考下
    2014-10-10
  • java優(yōu)化hibernate性能的幾點(diǎn)建議

    java優(yōu)化hibernate性能的幾點(diǎn)建議

    以上是在進(jìn)行struts+hibernate+spring進(jìn)行項(xiàng)目開發(fā)中,對(duì)hibernate性能優(yōu)化的幾點(diǎn)心得。
    2008-10-10
  • java編程Reference核心原理示例源碼分析

    java編程Reference核心原理示例源碼分析

    這篇文章主要為大家介紹了java編程Reference的核心原理以及示例源碼分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪
    2022-01-01
  • SpringBoot輕松整合MongoDB的全過程記錄

    SpringBoot輕松整合MongoDB的全過程記錄

    這篇文章主要給大家介紹了關(guān)于SpringBoot輕松整合MongoDB的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01

最新評(píng)論

舒兰市| 深圳市| 澄迈县| 陆丰市| 西畴县| 锡林郭勒盟| 句容市| 阿拉善左旗| 洪湖市| 拜泉县| 时尚| 绥宁县| 敖汉旗| 翼城县| 玛多县| 周至县| 句容市| 荆州市| 城固县| 拜泉县| 六安市| 隆昌县| 宁晋县| 饶平县| 昌江| 樟树市| 额济纳旗| 卢氏县| 高陵县| 富蕴县| 云安县| 年辖:市辖区| 福建省| 平江县| 金门县| 新兴县| 许昌县| 大悟县| 黄龙县| 庆城县| 皋兰县|