SpringBoot自動裝配源碼

自動裝配:

實際上就是如何將Bean自動化裝載到IOC容器中管理,Springboot 的自動裝配時通過SPI 的方式來實現的

SPI:SpringBoot 定義的一套接口規范,這套規范規定:Springboot 在啟動時會掃描外部引用 jar 包中的META-INF/spring.factories文件,將文件中配置的類型信息加載到 Spring 容器,并執行類中定義的各種操作。對于外部 jar 來說,只需要按照 Springboot 定義的標準,就能將自己的功能裝置進 Springboot。

Springboot 通過@EnableAutoConfiguration開啟自動裝配,我們點進去發現一個@Import(AutoConfigurationImportSelector.class) 查看他的Diagrams發現它繼承于ImportSelector 在Spring源碼中見到過,那我們就找selectImports() 方法

在這里插入圖片描述

AutoConfigurationImportSelector → selectImports()

這里就是自動裝配的核心代碼了getAutoConfigurationEntry

@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {if (!isEnabled(annotationMetadata)) {return NO_IMPORTS;}AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {if (!this.isEnabled(annotationMetadata)) {return EMPTY_ENTRY;} else {AnnotationAttributes attributes = this.getAttributes(annotationMetadata);// 通過 SpringFactoriesLoader.loadSpringFactories() // 加載META-INF/spring.factories中的配置List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);// 去除重復項configurations = this.removeDuplicates(configurations);// 應用exclusion屬性,排除掉的引入// 開發過程中某些服務不需要的配置信息可以在注解后加上(exclude = xxxAutoConfiguration.class)來排除加載Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);this.checkExcludedClasses(configurations, exclusions);configurations.removeAll(exclusions);// 檢查候選配置類上的注解@ConditionalOnClass// 如果要求的類不存在,則這個候選類會被過濾不被加載configurations = this.getConfigurationClassFilter().filter(configurations);this.fireAutoConfigurationImportEvents(configurations, exclusions);return new AutoConfigurationEntry(configurations, exclusions);}
}

通過this.getCandidateConfigurations()發現是SpringFactoriesLoader.loadSpringFactories() 加載META-INF/spring.factories中的配置來實現的

private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {Map<String, List<String>> result = (Map)cache.get(classLoader);if (result != null) {return result;} else {Map<String, List<String>> result = new HashMap();try {Enumeration<URL> urls = classLoader.getResources("META-INF/spring.factories");while(urls.hasMoreElements()) {URL url = (URL)urls.nextElement();UrlResource resource = new UrlResource(url);Properties properties = PropertiesLoaderUtils.loadProperties(resource);Iterator var6 = properties.entrySet().iterator();while(var6.hasNext()) {Map.Entry<?, ?> entry = (Map.Entry)var6.next();String factoryTypeName = ((String)entry.getKey()).trim();String[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());String[] var10 = factoryImplementationNames;int var11 = factoryImplementationNames.length;for(int var12 = 0; var12 < var11; ++var12) {String factoryImplementationName = var10[var12];((List)result.computeIfAbsent(factoryTypeName, (key) -> {return new ArrayList();})).add(factoryImplementationName.trim());}}}result.replaceAll((factoryType, implementations) -> {return (List)implementations.stream().distinct().collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));});cache.put(classLoader, result);return result;} catch (IOException var14) {throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var14);}}
}

this.getConfigurationClassFilter().filter(configurations) 這里是如何過濾的我們繼續深入看一下在內部類ConfigurationClassFilter的實現

在這里插入圖片描述

ConfigurationClassFilter.java中autoConfigurationMetadata 屬性在構造函數中進行了賦值,查看loadMetadata() 發現是根據PATH = "META-INF/spring-autoconfigure-metadata.properties" 文件中的信息進行判斷的

protected static final String PATH = "META-INF/spring-autoconfigure-metadata.properties";private AutoConfigurationMetadataLoader() {}static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader) {return loadMetadata(classLoader, PATH);}static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader, String path) {try {Enumeration<URL> urls = (classLoader != null) ? classLoader.getResources(path): ClassLoader.getSystemResources(path);Properties properties = new Properties();while (urls.hasMoreElements()) {properties.putAll(PropertiesLoaderUtils.loadProperties(new UrlResource(urls.nextElement())));}return loadMetadata(properties);}catch (IOException ex) {throw new IllegalArgumentException("Unable to load @ConditionalOnClass location [" + path + "]", ex);}}

我們拿出META-INF/spring-autoconfigure-metadata.properties 中一部分數據

org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration$MessagingTemplateConfiguration=
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration$MessagingTemplateConfiguration.ConditionalOnClass=org.springframework.amqp.rabbit.core.RabbitMessagingTemplate

分析發現如果項目中不存在org.springframework.amqp.rabbit.core.RabbitMessagingTemplate 這個類,那么在容器啟動時就不加載。也就是說我們用的時候直接引入這個starter,啟動的時候就會加載這個starter里的配置,不引入就不加載。META-INF/spring.factories 里的自動加載信息是為了方便我們后期引入不需要額外再進行配置。

總結:

Srpingboot使用@EnableAutoConfiguration 注解開啟自動裝配,通過SpringFactoriesLoader.*loadFactoryNames()*加載META-INF/spring.factories中的自動配置類實現自動裝配,通過@ConditionalOn...按需加載的配置類過濾掉未引入用不到的項

@ConditionalOn 條件注解:

@ConditionalOnBean:當容器里有指定 Bean 的條件下

@ConditionalOnMissingBean:當容器里沒有指定 Bean 的情況下

@ConditionalOnSingleCandidate:當指定 Bean 在容器中只有一個,或者雖然有多個但是指定首選 Bean

@ConditionalOnClass:當類路徑下有指定類的條件下

@ConditionalOnMissingClass:當類路徑下沒有指定類的條件下

@ConditionalOnProperty:指定的屬性是否有指定的值

@ConditionalOnResource:類路徑是否有指定的值

@ConditionalOnExpression:基于 SpEL 表達式作為判斷條件

@ConditionalOnJava:基于 Java 版本作為判斷條件

@ConditionalOnJndi:在 JNDI 存在的條件下差在指定的位置

@ConditionalOnNotWebApplication:當前項目不是 Web 項目的條件下

@ConditionalOnWebApplication:當前項目是 Web 項 目的條件下

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/18263.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/18263.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/18263.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

css 漸變色邊框

效果圖&#xff1a; 代碼&#xff1a; <style>:root{--br-radius: 12px;}.list{position: relative;}.list_tle{margin-top: 15px;margin-bottom: 5px;}.item{position: relative;display: inline-flex;} .br1 {padding: 10px 16px;clip-path: inset(0 round 6px);borde…

官宣|HelpLook現已入駐釘釘應用市場,助力企業知識管理知識

前一陣子OpenAI公司最新的GPT-4o技術震撼發布&#xff0c;人工智能的實際應用前景再次引起行業矚目&#xff0c;或者被GPT4o的數據分析等特色功能折服。如您正尋求將AI技術融入企業知識管理&#xff0c;不要錯過HelpLook&#xff01;HelpLook AI知識庫已經正式入駐釘釘應用市場…

Flutter 中的 SlideTransition 小部件:全面指南

Flutter 中的 SlideTransition 小部件&#xff1a;全面指南 在 Flutter 中&#xff0c;SlideTransition 是一個動畫組件&#xff0c;用于創建滑動動畫效果&#xff0c;使得子組件可以沿著一個軸滑動進入或滑動退出視圖。這種動畫效果常用于頁面轉場、菜單展開收起、元素的添加…

2024-5-8——給植物澆水

2024-5-8 題目來源我的題解方法一 模擬 題目來源 力扣每日一題&#xff1b;題序&#xff1a;2079 我的題解 方法一 模擬 依次模擬澆水動作 使用一個變量 cap維護剩余的水量&#xff0c;使用t作為還未澆水的樹的下標。當從第 i?1株植物到達第 i株植物時&#xff1a; 如果 ca…

前端中css穿透樣式:deep的用法

在前端開發中&#xff0c;尤其是使用 Vue.js 這樣的框架時&#xff0c;有時我們需要在子組件中修改或影響由父組件傳遞下來的樣式。然而&#xff0c;由于組件的封裝和樣式隔離&#xff0c;直接修改子組件中的樣式可能不起作用。這時&#xff0c;我們可以使用 ::v-deep 偽元素來…

基于Android的家庭理財APP的設計與實現(論文+源碼)_kaic

摘 要 隨著我國居民收入和生活水平的提高&#xff0c;家庭理財成為人們熱議的焦點問題。在需求分析階段&#xff0c;系統從用戶的實際需求出發&#xff0c;確定了用戶賬戶管理、記賬、數據分析和提醒功能等幾個核心需求。用戶賬戶管理包括用戶注冊、登錄和密碼找回等基本操作…

【4th chapter】信息安全技術—安全技術、安全架構、安全策略、安全管理、軟件的脆弱性

概要 安全技術安全架構安全策略安全管理軟件的脆弱性加密技術&#xff08;Encryption Technology&#xff09;安全域架構&#xff08;Security Domain Architecture&#xff09;訪問控制策略&#xff08;Access Control Policy&#xff09;信息安全管理體系&#xff08;Inform…

面試數據庫八股文十問十答第六期

面試數據庫八股文十問十答第六期 作者&#xff1a;程序員小白條&#xff0c;個人博客 相信看了本文后&#xff0c;對你的面試是有一定幫助的&#xff01;關注專欄后就能收到持續更新&#xff01; ?點贊?收藏?不迷路&#xff01;? 1&#xff09;來說說一條 SQL 語句的執行…

leetcode題目238

除自身以外的數組的乘積 中等 給你一個整數數組 nums&#xff0c;返回 數組 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘積 。 題目數據 保證 數組 nums之中任意元素的全部前綴元素和后綴的乘積都在 32 位 整數范圍內。 請 不要使用除法&…

大數據技術Hbase列數據庫——topic1

目錄 搭建單機版Hbase驗證方法一驗證方法二 搭建單機版Hbase 驗證方法一 使用 jps 命令查看 HMaster 進程是否啟動 首先使用xftp 7上傳hbase-2.1.0安裝壓縮包到虛擬機進行解壓縮到某一地址&#xff0c;這里解壓縮到了上傳的路徑即/root/software/ tar -zxvf hbase-2.1.0-bi…

進程與線程學習

多線程 tthreading.Thread(targettask,arge(11,)) start&#xff08;&#xff09;開始 join&#xff08;&#xff09;等待 主線程在默認情況下會等待所有非守護線程&#xff08;子線程&#xff09;結束后才會結束程序。也就是說&#xff0c;如果主線程在結束前沒有調用所有…

2025第十屆美陳展

展位又遭瘋搶&#xff01;2025第十屆美陳展釋放“無界之美” 美是全球通用的語言&#xff0c;人類對美的追求始終如一&#xff0c;大眾審美在經歷了時代的變遷后開始趨同&#xff0c;東方文明深處的美學經濟開始崛起。 在如今商業邁入存量階段&#xff0c;以品牌為突破口打造…

基于 vuestic-ui 實戰教程 - 登錄篇

1. 簡介 登錄做為一個系統的門面&#xff0c;也是阻擋外界的一道防線&#xff0c;那在vuestic-ui中如何做登錄功能呢。在這里就之間沿用初始版本的Login頁面&#xff0c;作為一個演示模板&#xff0c;后續需要改進的讀者可以在此篇文章的基礎上修改。 2. 登錄接口相關api 與 t…

python連接mysql,并整理(去哪兒網)頁面數據到表

##引入requests/pymysql模塊 本地安裝mysql數據庫&#xff0c;安裝圖形化工具navicat import requests from pymysql import Connect#創建客戶端連接信息 client Connect(host127.0.0.1,port3306,userroot,password, ) #創建游標 cursor client.cursor() cursor.execute(cre…

17- PHP 開發-個人博客項目TP 框架路由訪問安全寫法歷史漏 洞

常見的php框架&#xff1a;laravel和thinkphp和yii 這里以thinkphp為例 thinkphp目錄訪問設置 這里只找到了這個3.多的源代碼&#xff0c;沒找點5.的&#xff0c;湊合一下 鏈接&#xff1a;GitHub - top-think/thinkphp: ThinkPHP3.2 ——基于PHP5的簡單快速的面向對象的PHP…

HTML用法介紹

文章目錄 一、HTML概念和模版二、常用標簽及用法1.p標簽2.span標簽3.h標簽4.hr標簽5.img標簽6.a標簽7.input標簽8.table標簽 一、HTML概念和模版 HTML的全稱為超文本標記語言&#xff0c;它包括一系列標簽組成&#xff0c;模版及各部分注釋如下&#xff1a; <!--聲明文檔類…

ROS基礎學習-話題通信機制研究

研究ROS通信機制 研究ROS通信機制 0.前言1.話題通信1.1 理論模型1.2 話題通訊的基本操作1.2.1 C++1.2.2 Python中使用自己的虛擬環境包1.2.2.1 參考11.2.2.2 參考21.2.2.3 /usr/bin/env:“python”:沒有那個文件或目錄1.2.3 Python1.2.2.1 發布方1.2.2.2 訂閱方1.2.2.3 添加可執…

【八股系列】談談關于對webpack熱更新的原理?

文章目錄 1. 熱更新原理2. 熱更新配置 1. 熱更新原理 Webpack 的熱模塊替換&#xff08;Hot Module Replacement&#xff0c;HMR&#xff09;是一種在不完全刷新頁面的情況下更新應用代碼的技術&#xff0c;從而提高了開發效率。以下是 HMR 的核心原理&#xff1a; 步驟描述1…

tcpdump抓包,抓包導出.pcap文件用wireshark看

1、抓所有口的包 tcpdump -i any host 設備的ip2、抓特定口的包 tcpdump -i eth2 port 61182 -nne3、將抓到的包導出到pacb文件 tcpdump -i eth2 port 61182 -nne -s0 -w /tmp/61182.pcap -s0: Sets the snapshot length to capture the entire packet. The 0 means that tcpd…

《征服數據結構》目錄

我們知道要想學好算法&#xff0c;必須熟練掌握數據結構&#xff0c;數據結構常見的有 8 大類&#xff0c;分別是數組&#xff0c;鏈表&#xff0c;隊列&#xff0c;棧&#xff0c;散列表&#xff0c;樹&#xff0c;堆&#xff0c;圖。但如果細分的話就比較多了&#xff0c;比如…