spring源碼解析-(1)關于Bean

什么是Bean?

是spring對所有注入到IoC容器中的類的統稱。

我們要注冊進入spirng的bean千奇百怪,所以spring必須需要使用一個統一的定義來標識bean,就有了接下來的BeandDefinition,通過名稱我們就可以知道,他是對bean的定義。

Spring的BeanDefinition詳解

效果:將不同來源的bean進行歸一化處理

什么是BeandDefinition? 下面是BeanDefinition的源碼,BeanDefinition是一個接口,他繼承了兩個接口,分別是AttributeAccessor和BeanMetadataElement。

簡單來說,spring將所有需要裝在到容器中的類進行了歸一化處理,他們的共同屬性都通過BeanDefinition去約束。

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;int ROLE_APPLICATION = 0;int ROLE_SUPPORT = 1;int ROLE_INFRASTRUCTURE = 2;void setParentName(@Nullable String parentName);@NullableString getParentName();void setBeanClassName(@Nullable String beanClassName);@NullableString getBeanClassName();void setScope(@Nullable String scope);@NullableString getScope();void setLazyInit(boolean lazyInit);boolean isLazyInit();void setDependsOn(@Nullable String... dependsOn);@NullableString[] getDependsOn();void setAutowireCandidate(boolean autowireCandidate);boolean isAutowireCandidate();void setPrimary(boolean primary);boolean isPrimary();void setFactoryBeanName(@Nullable String factoryBeanName);@NullableString getFactoryBeanName();void setFactoryMethodName(@Nullable String factoryMethodName);@NullableString getFactoryMethodName();ConstructorArgumentValues getConstructorArgumentValues();default boolean hasConstructorArgumentValues() {return !getConstructorArgumentValues().isEmpty();}MutablePropertyValues getPropertyValues();default boolean hasPropertyValues() {return !getPropertyValues().isEmpty();}void setInitMethodName(@Nullable String initMethodName);@NullableString getInitMethodName();void setDestroyMethodName(@Nullable String destroyMethodName);@NullableString getDestroyMethodName();void setRole(int role);int getRole();void setDescription(@Nullable String description);@NullableString getDescription();ResolvableType getResolvableType();boolean isSingleton();boolean isPrototype();boolean isAbstract();@NullableString getResourceDescription();@NullableBeanDefinition getOriginatingBeanDefinition();
}

從代碼中,我們可以看出,BeanDefinition一共有兩種實現類型,一種是AnnotatedBeanDefinition,另一種則是AbstractBeanDefinition。

不難看出,AnnotatedBeanDefinition是對BeanDefinition接口的擴展,而AbstractBeanDefinition是一個抽象方法, 實現了大部分的模板方法,以便子類去使用。

在這里插入圖片描述

有了存儲類的統一元數據結構,那么spring將需要一種特定的數據結構去存儲這些內容,spring提供了這么一個接口BeanDefinitionRegistry,能力如下:

public interface BeanDefinitionRegistry extends AliasRegistry {void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)throws BeanDefinitionStoreException;void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;boolean containsBeanDefinition(String beanName);String[] getBeanDefinitionNames();int getBeanDefinitionCount();boolean isBeanNameInUse(String beanName);
}

通過BeanDefinitionRegistry中提供的方法中我們可以看到他擁有什么能力,首先將名稱和對應的beanDefinition進行匹配。

其次,通過getBeanDefinitionNames,不難看出我們可以一個beandefinition可以擁有多個別名。

可以通過BeanDefinitionRegistry的實現類來窺探spring究竟是如何存儲的,其實很簡單,是通過一個map進行存儲的。

具體代碼如下:

public class SimpleBeanDefinitionRegistry extends SimpleAliasRegistry implements BeanDefinitionRegistry {private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(64);@Overridepublic void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)throws BeanDefinitionStoreException {Assert.hasText(beanName, "'beanName' must not be empty");Assert.notNull(beanDefinition, "BeanDefinition must not be null");this.beanDefinitionMap.put(beanName, beanDefinition);}@Overridepublic void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {if (this.beanDefinitionMap.remove(beanName) == null) {throw new NoSuchBeanDefinitionException(beanName);}}@Overridepublic BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {BeanDefinition bd = this.beanDefinitionMap.get(beanName);if (bd == null) {throw new NoSuchBeanDefinitionException(beanName);}return bd;}@Overridepublic boolean containsBeanDefinition(String beanName) {return this.beanDefinitionMap.containsKey(beanName);}@Overridepublic String[] getBeanDefinitionNames() {return StringUtils.toStringArray(this.beanDefinitionMap.keySet());}@Overridepublic int getBeanDefinitionCount() {return this.beanDefinitionMap.size();}@Overridepublic boolean isBeanNameInUse(String beanName) {return isAlias(beanName) || containsBeanDefinition(beanName);}
}

通過registerBeanDefinition方法可以看出,將beanName與beanDefinition進行綁定,多個beanName可以綁定同一個beanDefinition。

怎樣去使用BeanDefinition的實現類呢?

首先創建一個實體類:

@Component // 后面測試注解的方式用到的
public class Person {private Integer id;private String name;public Person() {}public Person(Integer id, String name) {this.id = id;this.name = name;}@Overridepublic String toString() {return "Person{" +"id=" + id +", name='" + name + '\'' +'}';}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}
}

1、通過讀取xml中的數據

xml代碼如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="person" class="com.test.entity.Person"><property name="id" value="1"/><property name="name" value="不會敲代碼的呂小橋"/></bean></beans>

測試類:

BeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
BeanDefinitionReader reader = new XmlBeanDefinitionReader(registry);
reader.loadBeanDefinitions("test.xml");
System.out.println(registry.getBeanDefinitionCount());

輸出內容:

> Task :spring-test:BeanDefinitionTest.main()
1

2、通過注解的方式讀取bean

注意:Person類需要加上Component注解

測試方法

BeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(registry);
reader.register(Person.class);
System.out.println(registry.getBeanDefinitionNames());

輸出如下:

org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
person
org.springframework.context.event.internalEventListenerFactory
org.springframework.context.annotation.internalAutowiredAnnotationProcessor

3、通過包掃描的方式讀取bean

測試方法:

// 掃描指定包下的所有類
BeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
// 掃描指定包下的所有類
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(registry);
scanner.scan("com.test.entity");
for (String beanDefinitionName : registry.getBeanDefinitionNames()) {System.err.println(beanDefinitionName);
}

輸出結果:

org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
person
org.springframework.context.event.internalEventListenerFactory
org.springframework.context.annotation.internalAutowiredAnnotationProcessor

思考總結:

1、在查看源碼的過程中,發現源碼中有很多地方用到了如下代碼:

Assert.hasText(beanName, "'beanName' must not be empty");

以上代碼可以有效的避免我們在開發中大量的if判斷,同時可以讓你的代碼可閱讀性更高。

hutools和spring依賴中均有該類型的寫法,可以參考一下。

2、設計模式&接口&抽象類,幫助更好的處理一系列方法

在面對一系列處理的時候,我們應該抽象出接口,并使用抽象類去約定模板方法,繼而使用子類去實現,這種方式會節省我們大量重復的工作,而且所有的方法都有跡可循,在模板方法中定義流程,在子類中實現,能夠有效的解耦流程和實現。這樣我們就可以只關心子類的具體實現了。

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

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

相關文章

美國演員工會SAG-AFTRA 要求人工智能在廣告中使用演員聲音需征得同意并付費

SAG-AFTRA 的新豁免允許在人工智能生成的廣告中使用演員的聲音&#xff0c;但需要同意、補償和安全措施 美國演員工會&#xff08;SAG-AFTRA&#xff09;推出了一項新的豁免&#xff0c;以保護會員免受未經授權的人工智能在廣告中使用其聲音的影響。動態人工智能音頻廣告豁免定…

C語言Kruskal算法求最小生成樹

Kruskal算法求出最小生成樹。 圖形 算法描述 先找最小權值邊為1的邊有&#xff08;V1&#xff0c;V4&#xff09;&#xff0c;&#xff08;V2&#xff0c;V9&#xff09;&#xff0c;保證不產生回路就可以成功選擇邊 除去上一次找的邊后&#xff0c;在找權值最小的邊為2的有&a…

制作AI問答機器人:從0到1的完整指南

在數字化轉型的浪潮中&#xff0c;企業正追求更高效、智能的客戶服務解決方案。AI問答機器人以其快速響應、全天候服務和持續學習的能力&#xff0c;成為了提升客戶滿意度和加速業務發展的關鍵工具。本文將深入探討如何制作一個企業級的AI問答機器人&#xff0c;并強調其功能體…

OpenAI發表研究論文 介紹了一種逆向工程AI模型工作原理的方法

ChatGPT 開發商 OpenAI 構建人工智能的方法本周遭到了前員工的抨擊&#xff0c;他們指責該公司利用可能有害的技術冒不必要的風險。今天&#xff0c;OpenAI 發布了一篇新的研究論文&#xff0c;目的顯然是為了表明它在通過提高模型的可解釋性來應對人工智能風險方面的認真態度。…

hot100 -- 二分查找

目錄 前言 &#x1f382;搜索插入位置 &#x1f33c;搜索二維矩陣 &#x1f33c;排序數組元素第一和最后一個位置 &#x1f33c;旋轉排序數組 &#x1f4aa;旋轉排序數組中的最小值 &#x1f4aa;兩個正序數組的中位數 前言 二分算法學習_時間超限ac:0%-CSDN博客 &#…

2024年【起重機械指揮】考試及起重機械指揮新版試題

題庫來源&#xff1a;安全生產模擬考試一點通公眾號小程序 起重機械指揮考試考前必練&#xff01;安全生產模擬考試一點通每個月更新起重機械指揮新版試題題目及答案&#xff01;多做幾遍&#xff0c;其實通過起重機械指揮試題及解析很簡單。 1、【多選題】《中華人民共和國特…

【Androi】安卓發展歷程詳解

人不走空 &#x1f308;個人主頁&#xff1a;人不走空 &#x1f496;系列專欄&#xff1a;算法專題 ?詩詞歌賦&#xff1a;斯是陋室&#xff0c;惟吾德馨 目錄 &#x1f308;個人主頁&#xff1a;人不走空 &#x1f496;系列專欄&#xff1a;算法專題 ?詩詞歌…

git推送代碼到github拒絕推送的解決方案

這里描述一下本地推送的場景&#xff0c;首先我在碼云上建立了一個前端項目&#xff0c;進行了自己的個性化開發&#xff0c;后期在github上創建了一個一樣的項目倉庫存放代碼。使用webstorm進行代碼開發。在下面這個位置可以選擇推送的代碼位置。 選擇推送github倉庫之后&…

Python深度學習基于Tensorflow(16)基于Tensorflow的對話實例

文章目錄 基礎數據清洗數據生成詞匯表定義分詞器并制作數據集構建Transformer模型并訓練模型推理 Tensorflow 的核心就是注意力機制&#xff0c;在之前詳細的介紹過&#xff0c;具體可以看這個&#xff1a;Python深度學習基于Tensorflow&#xff08;9&#xff09;注意力機制_te…

在Java中為什么對a賦值為10,在進行a++時還是等于10呢

首先我們看這樣一組代碼 public class demo1 {public static void main(String[] args) {int a10;aa;System.out.println(a);} } 結果&#xff1a;10不是在第二步有a操作嗎&#xff1f;為什么還是10呢&#xff1f; a的執行步驟如下&#xff1a; 保存當前a的值&#xff08;即10…

websocket鏈接攜帶參數

前端創建鏈接時官方提供的構造函數 var aWebSocket new WebSocket(url, [protocols]); url&#xff1a;要連接的URL&#xff1b;這應該是WebSocket服務器將響應的URL。 protocols&#xff1a;可選&#xff1b;一個協議字符串或者一個包含協議字符串的數組。這些字符串用于指定…

智能語音電銷機器人可以做哪些事情?ai語音機器人系統

智能語音電銷機器人軟件的出現&#xff0c;給很多企業都帶來了福利&#xff0c;尤其是電銷企業&#xff0c;不僅工作效率提升了&#xff0c;成本降低了&#xff0c;還能實現智能化管理客戶的出現&#xff0c;給很多企業都帶來了福利&#xff0c;尤其是電銷企業&#xff0c;不僅…

python初學者筆記(八)——數字階乘

#python初學者筆記&#xff08;8&#xff09;——數字階乘 階乘是基斯頓卡曼于 1808 年發明的運算符號,是數學術語,一個正整數的階乘(factorial)是所有小于及等于該數的正整數的積。 下面利用Python編寫數字階乘 ##1.方法一:利用函數的方法&#xff0c;求輸入值的階乘 #coding…

WebAPI 前端開發流程:深度解析與實踐探索

WebAPI 前端開發流程&#xff1a;深度解析與實踐探索 在前端開發的世界里&#xff0c;WebAPI扮演著至關重要的角色&#xff0c;它作為前端與后端溝通的橋梁&#xff0c;確保了數據的流暢傳輸與功能的完整實現。本文將詳細探討WebAPI前端開發流程&#xff0c;從四個方面、五個方…

什么情況下需要配戴助聽器

以下幾種情況需要考慮配戴助聽器&#xff1a; 1、聽力無波動3個月以上的感音神經性聽力障礙。如:先天性聽力障礙、老年性聽力障礙、噪聲性聽力障礙、突聾的穩定期等&#xff0c;均可選配合適的助聽器。 2、年齡方面。使用助聽器沒有嚴格的年齡限制&#xff0c;從出生數周的嬰…

深度學習Week16——數據增強

文章目錄 深度學習Week16——數據增強 一、前言 二、我的環境 三、前期工作 1、配置環境 2、導入數據 2.1 加載數據 2.2 配置數據集 2.3 數據可視化 四、數據增強 五、增強方式 1、將其嵌入model中 2、在Dataset數據集中進行數據增強 六、訓練模型 七、自定義增強函數 一、前言…

Geoserver源碼解讀一(環境搭建)

一、Github地址 https://github.com/geoserver/geoserver 1.1 克隆代碼 git clone https://github.com/geoserver/geoserver.git 1.2 選擇版本 版本選擇參考我的上一篇文章 Geoserver 以及 Geotools各版本和jdk版本對照表 此處我選擇的是兼容jdk8的最后一個版本 git che…

netty+springboot+vue聊天室(需要了解netty)

先看看這個使用websocket實現的聊天室&#xff0c;因為前端是使用websocket&#xff0c;和下面的demo的前端差不多就不解釋實現原理&#xff0c;所以建議還是看看(要是會websocket的大佬請忽略) springbootwebsocketvue聊天室 目錄 一、實現內容二、代碼實現1.后端2.前端源碼…

html+CSS+js部分基礎運用17

在圖書列表中&#xff0c;為書名“零基礎學JavaScript”和“HTML5CSS3精彩編程200例”添加顏色。&#xff08;請用class或style屬性實現&#xff09;&#xff0c;效果如下圖1所示&#xff1a; 圖1 圖書列表 Class和style的綜合應用。&#xff08;1&#xff09;應用class的對象、…

命令行打包最簡單的android項目從零開始到最終apk文件

準備好需要的工具 AndroidDevTools - Android開發工具 Android SDK下載 Android Studio下載 Gradle下載 SDK Tools下載 jdk的鏈接我就不發出來,自己選擇,我接下來用的是8版本的jdk和android10的sdk sdk的安裝和環境變量的配置 sdk tool壓縮包打開后是這樣子,打開sdk mana…