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

Java 自定義Spring框架與Spring IoC相關(guān)接口分析

 更新時間:2021年10月14日 10:17:58   作者:李阿昀  
Spring框架是由于軟件開發(fā)的復雜性而創(chuàng)建的。Spring使用的是基本的JavaBean來完成以前只可能由EJB完成的事情。然而,Spring的用途不僅僅限于服務器端的開發(fā)

在本講,我們來對Spring IoC功能相關(guān)的接口逐一進行分析,分析這些接口的原因就是為了我們自己定義Spring IoC功能提前做好準備。

Spring IoC相關(guān)接口分析

BeanFactory接口解析

對于BeanFactory接口,我之前只是稍微提到過,并且將就著用了一下它。這里,我將會對BeanFactory接口進行一個具體講解。

Spring中bean的創(chuàng)建是典型的工廠模式,這一系列的bean工廠,即IoC容器,為開發(fā)者管理對象之間的依賴關(guān)系提供了很多便利和基礎(chǔ)服務,在Spring中有許多IoC容器的實現(xiàn)可供用戶選擇,其相互關(guān)系如下圖所示。

在這里插入圖片描述

這里說到了Spring中bean的創(chuàng)建是典型的工廠模式,那么你知道到底是哪種工廠模式嗎?其實,這里面用的是簡單工廠+配置文件的形式,相信大家都知道簡單工廠+配置文件會大大降低對象和對象之間的耦合。

上面還說到了在Spring中有許多IoC容器的實現(xiàn)可供用戶選擇,這句話怎么理解呢?我們在創(chuàng)建IoC容器時,創(chuàng)建的肯定是BeanFactory接口的子實現(xiàn)類對象,那么我們就要想了,到底有哪些子實現(xiàn)類可供咱選擇呢?嘿嘿!這不用你操心,因為Spring提供了很多該接口的子實現(xiàn)類供我們?nèi)ミx擇。

從以上類圖中可以看到,BeanFactory作為最頂層的一個接口,定義了IoC容器的基本功能規(guī)范,而且BeanFactory有三個重要的子接口,分別是ListableBeanFactory、HierarchicalBeanFactory和AutowireCapableBeanFactory。但是從類圖中我們可以發(fā)現(xiàn)最終的默認實現(xiàn)類是DefaultListableBeanFactory,它實現(xiàn)了所有的接口,這就意味著如果我們想要用的話,那么直接用該子實現(xiàn)類就行了!

看完上面這段話,有兩點需要引起我們的注意,一是BeanFactory作為最頂層的一個接口,定義了IoC容器的基本功能規(guī)范,那么到底它定義了哪些最基本的功能規(guī)范呢?其實,大家想一想就知道了,工廠本身就是用來生產(chǎn)對象的,那么在Spring里面,bean工廠生產(chǎn)的就是bean對象了,所以BeanFactory里面肯定是要提供獲取bean對象的方法的,這個我后面就會詳細地講到;二是BeanFactory屬于延時加載,也就是說對于bean對象Spring進行了一個延時加載。

問題來了,為何要定義這么多層次的接口呢?定義的少一點,整個架構(gòu)看起來不就更加簡單嗎?原因如下:

每個接口都有它的使用場合,主要是為了區(qū)分在Spring內(nèi)部操作過程中對象的傳遞和轉(zhuǎn)化,對對象的數(shù)據(jù)訪問所做的限制。例如,

  • ListableBeanFactory接口:表示bean可列表化。什么意思啊?我給大家解釋解釋,它說的是該接口可以通過列表的方式對bean對象進行一個存儲。
  • HierarchicalBeanFactory接口:表示bean是有繼承關(guān)系的,也就是每個bean可能有父bean。
  • AutowireCapableBeanFactory接口:定義bean的自動裝配規(guī)則。依賴注入就屬于自動裝配規(guī)則里面的。

以上這三個接口共同定義了bean的集合、bean之間的關(guān)系及bean的行為。不過,最基本的IoC容器接口還是BeanFactory,下面我們就來看一下它的源碼,看它里面到底定義了哪些最基本的功能規(guī)范。

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package org.springframework.beans.factory;

import org.springframework.beans.BeansException;
import org.springframework.core.ResolvableType;
import org.springframework.lang.Nullable;

public interface BeanFactory {
    String FACTORY_BEAN_PREFIX = "&";

    // 根據(jù)bean的名稱獲取IoC容器中的bean對象
    Object getBean(String var1) throws BeansException;

    // 根據(jù)bean的名稱獲取IoC容器中的bean對象,并指定獲取到的bean對象的類型,這樣我們使用時就不需要進行類型強轉(zhuǎn)了
    <T> T getBean(String var1, Class<T> var2) throws BeansException;

    Object getBean(String var1, Object... var2) throws BeansException;

    <T> T getBean(Class<T> var1) throws BeansException;

    <T> T getBean(Class<T> var1, Object... var2) throws BeansException;

    <T> ObjectProvider<T> getBeanProvider(Class<T> var1);

    <T> ObjectProvider<T> getBeanProvider(ResolvableType var1);

    // 判斷容器中是否包含指定名稱的bean對象
    boolean containsBean(String var1);

    // 根據(jù)bean的名稱判斷是否是單例
    boolean isSingleton(String var1) throws NoSuchBeanDefinitionException;

    boolean isPrototype(String var1) throws NoSuchBeanDefinitionException;

    boolean isTypeMatch(String var1, ResolvableType var2) throws NoSuchBeanDefinitionException;

    boolean isTypeMatch(String var1, Class<?> var2) throws NoSuchBeanDefinitionException;

    @Nullable
    Class<?> getType(String var1) throws NoSuchBeanDefinitionException;

    @Nullable
    Class<?> getType(String var1, boolean var2) throws NoSuchBeanDefinitionException;

    String[] getAliases(String var1);
}

看到那一系列的getBean方法沒,它們都是用來獲取bean對象的,當然了,BeanFactory接口里面還定義了一些其他的基本功能規(guī)范,這里我就不再細說了。

在BeanFactory里只對IoC容器的基本行為做了定義,根本不關(guān)心你的bean是如何定義及怎樣加載的。正如我們只關(guān)心能從工廠里得到什么產(chǎn)品,而不關(guān)心工廠是怎么生產(chǎn)這些產(chǎn)品的一樣。當然,bean的定義以及加載是要交由給BeanFactory接口的子實現(xiàn)類去做的。

BeanFactory有一個很重要的子接口,就是ApplicationContext接口,該接口主要是來規(guī)范容器中的bean對象是非延時加載的,即在創(chuàng)建容器對象的時候就對bean對象進行初始化,并存儲到一個容器中。大家不妨來看一下下面這張圖。

在這里插入圖片描述

可以看到最頂層就是BeanFactory接口,它下面有一個子接口叫ApplicationContext,而該子接口下面又有三個比較重要的子實現(xiàn)類,還記得上面我說過在Spring中有許多IoC容器的實現(xiàn)可供用戶選擇嗎?這仨子實現(xiàn)類就是。如果要想知道工廠是如何產(chǎn)生對象的,那么我們就需要查看具體的IoC容器實現(xiàn)了,Spring提供了許多IoC容器實現(xiàn),比如:

  • FileSystemXmlApplicationContext:根據(jù)系統(tǒng)路徑加載XML配置文件,并創(chuàng)建IoC容器對象。
  • ClassPathXmlApplicationContext:根據(jù)類路徑加載XML配置文件,并創(chuàng)建IoC容器對象。
  • AnnotationConfigApplicationContext:加載注解類配置,并創(chuàng)建IoC容器。

注意了,我們在后面自己去定義Spring IoC功能時,我們只針對ClassPathXmlApplicationContext類來實現(xiàn),也就是只關(guān)注類路徑下XML配置文件的解析與對應IoC容器的創(chuàng)建。

關(guān)于BeanFactory接口的分析,我們就分析至此。

BeanDefinition接口解析

Spring IoC容器管理的是我們定義的各種bean對象及其相互關(guān)系,而bean對象在Spring實現(xiàn)中是以BeanDefinition來描述的。

來看一下下面配置文件中的bean配置,如果你用過Spring或者Spring MVC框架的話,那么相信你對這段配置肯定不會陌生,注意了,在<bean>標簽內(nèi)我們還可以設(shè)置很多屬性,例如scope、init-method、destory-method等,只是在這里我們并沒有全部列舉出來。

<bean id="userDao" class="com.meimeixia.dao.impl.UserDaoImpl"></bean>

現(xiàn)在對于Spring來說的話,它就得解析這個<bean>標簽了,解析時,必然就要把該<bean>標簽對應的屬性的值進行一個封裝,那Spring會封裝成什么樣的一個對象呢?會封裝成BeanDefinition對象,又由于BeanDefinition是一個接口,所以最終Spring會封裝成一個該接口的子實現(xiàn)類對象。

接下來,我們就來看看BeanDefinition接口的繼承體系,如下圖所示。

在這里插入圖片描述

可以看到,BeanDefinition確實是一個接口,而且它下面有一個具體的子實現(xiàn)類,即RootBeanDefinition。

BeanDefinitionReader接口解析

剛才我們講解完了BeanDefinition接口,知道了該接口的作用就是對XML配置文件里面<bean>標簽相關(guān)的屬性進行封裝。那么接下來我們就來思考一個問題,就是XML配置文件到底是由誰來解析的呢?既然提到解析了,那么我們就要來看一看BeanDefinitionReader接口了。

bean的解析過程非常復雜,功能被分得很細,因為這里需要被擴展的地方很多,必須保證足夠的靈活性,以應對可能的變化。bean的解析主要就是對Spring配置文件的解析,這個解析過程主要通過BeanDefinitionReader來完成。下面我們就來看看Spring中BeanDefinitionReader的類結(jié)構(gòu)圖,如下圖所示。

在這里插入圖片描述

當然了,你也可以回到IDEA里面去查看一下BeanDefinitionReader接口的繼承體系,如下圖所示。

在這里插入圖片描述

可以看到,BeanDefinitionReader接口有三個子實現(xiàn)類,這里我只講一下上面紅框框住的兩個子實現(xiàn)類。

  • PropertiesBeanDefinitionReader:主要解析properties格式的配置文件。但是,在實際開發(fā)中,你會發(fā)現(xiàn)很少會用到properties格式的配置文件,用的更多的是XML格式的配置文件。
  • XmlBeanDefinitionReader:主要解析XML格式的配置文件。

BeanDefinitionReader既然是一個接口的話,那么它里面定義的便是最基本的功能規(guī)范,這些規(guī)范針對不同的子實現(xiàn)類會有不同的實現(xiàn),從上圖中我們也看到了BeanDefinitionReader接口確實是有不同的子實現(xiàn)類。這些子實現(xiàn)類會來決定到底解析什么樣的配置文件,究竟是properties格式的呢,還是XML格式的,所以你會發(fā)現(xiàn)Spring底層設(shè)計的還是比較全面的。

接下來,我們就來看一下BeanDefinitionReader接口的源碼,看它里面到底定義了哪些最基本的功能規(guī)范。

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package org.springframework.beans.factory.support;

import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.lang.Nullable;

public interface BeanDefinitionReader {
    // 獲取BeanDefinitionRegistry注冊器對象
    BeanDefinitionRegistry getRegistry();

    @Nullable
    ResourceLoader getResourceLoader();

    @Nullable
    ClassLoader getBeanClassLoader();

    BeanNameGenerator getBeanNameGenerator();

    /*
     * 下面這些重載的loadBeanDefinitions方法都是從指定的資源中加載bean定義
     */
    int loadBeanDefinitions(Resource var1) throws BeanDefinitionStoreException;

    int loadBeanDefinitions(Resource... var1) throws BeanDefinitionStoreException;

    int loadBeanDefinitions(String var1) throws BeanDefinitionStoreException;

    int loadBeanDefinitions(String... var1) throws BeanDefinitionStoreException;
}

可以看到,BeanDefinitionReader接口里面定義了很多很多的方法,不過我們重點關(guān)注兩類方法:

  • getRegistry方法:獲取BeanDefinitionRegistry注冊器對象。
  • loadBeanDefinitions方法:從不同指定的資源中加載bean定義,也就是加載配置文件。

我相信,從BeanDefinitionReader接口定義的功能中你已經(jīng)理解了它具體的一個作用。

BeanDefinitionRegistry接口解析

接下來,我們來分析一下BeanDefinitionRegistry接口。其實,剛才我們在去分析BeanDefinitionReader接口的時候就見過,還記得嗎?BeanDefinitionReader接口里面的getRegistry方法的返回值類型就是BeanDefinitionRegistry。

我們都知道,BeanDefinitionReader是用來解析bean定義,并將其(指的就是bean定義)封裝成BeanDefinition對象的。還有,我想大家也知道我們定義的配置文件中會定義很多bean標簽,那么這里就存在一個問題了,就是解析出來的BeanDefinition對象到底存儲到哪兒了呢?答案就是BeanDefinition的注冊中心,而該注冊中心頂層接口就是BeanDefinitionRegistry。

接下來,我們就來看一下BeanDefinitionRegistry接口的源碼,看它里面到底定義了哪些最基本的功能規(guī)范。

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package org.springframework.beans.factory.support;

import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.core.AliasRegistry;

public interface BeanDefinitionRegistry extends AliasRegistry {
    // 往注冊表中注冊bean
    void registerBeanDefinition(String var1, BeanDefinition var2) throws BeanDefinitionStoreException;

    // 從注冊表中刪除指定名稱的bean
    void removeBeanDefinition(String var1) throws NoSuchBeanDefinitionException;

    // 獲取注冊表中指定名稱的bean
    BeanDefinition getBeanDefinition(String var1) throws NoSuchBeanDefinitionException;

    // 判斷注冊表中是否已經(jīng)注冊了指定名稱的bean
    boolean containsBeanDefinition(String var1);

    // 獲取注冊表中所有的bean的名稱
    String[] getBeanDefinitionNames();

    int getBeanDefinitionCount();

    boolean isBeanNameInUse(String var1);
}

以上就是注冊中心頂層接口BeanDefinitionRegistry里面定義的最基本的功能規(guī)范。

由于BeanDefinitionRegistry是一個接口,所以我們在使用的時候肯定就是使用它的子實現(xiàn)類了。接下來,我們就來看一下Spring中BeanDefinitionRegistry的類結(jié)構(gòu)圖,如下圖所示。

在這里插入圖片描述

當然了,你也可以回到IDEA里面去查看一下BeanDefinitionRegistry接口的繼承體系,如下圖所示。

在這里插入圖片描述

從上面可以看到BeanDefinitionRegistry接口的子實現(xiàn)類主要有以下幾個:

  • SimpleBeanDefinitionRegistry

從名字上來看,它就是一個簡單的BeanDefinition的注冊中心,由于解析出來的BeanDefinition對象就存儲在BeanDefinition的注冊中心,所以它必然是一個容器。在這里我要給大家提個醒,相比另外兩個類,該類是我們要更加要關(guān)注的。

接下來,我們就要看看該類里面有沒有定義什么容器來存儲BeanDefinition對象了。查看該類的源碼,如下圖所示,你會發(fā)現(xiàn)在其成員位置處定義了一個Map集合,而且Map集合的鍵是String類型的,值是BeanDefinition類型的。其實,從這里就可以看出,該Map集合就是用來注冊BeanDefinition對象的,其中,鍵就是要注冊的BeanDefinition對象的名稱,值就是要注冊的BeanDefinition對象,不知我這樣說,大家明白了沒?

在這里插入圖片描述

  • DefaultListableBeanFactory

該類我們在分析BeanFactory接口的時候就見過,還記得嗎?不記得的話,再回頭去看一下BeanFactory的類結(jié)構(gòu)圖。你會發(fā)現(xiàn)該類不僅實現(xiàn)了BeanFactory接口,還實現(xiàn)了BeanDefinitionRegistry接口,所以該類既是容器,也是注冊表。

接下來,我們也是要看看該類里面有沒有定義什么容器來存儲BeanDefinition對象。查看該類的源碼,如下圖所示,你會發(fā)現(xiàn)在其成員位置處也定義了一個Map集合來注冊BeanDefinition對象。

在這里插入圖片描述

  • GenericApplicationContext

該類間接地實現(xiàn)了ApplicationContext接口,這點你通過查閱源碼就能知道了,所以該類同上,既是容器,也是注冊表。

創(chuàng)建容器

剛才我們分析了一下與Spring IoC功能相關(guān)的一些接口,分析完這些接口之后,大家要明確的就是每一個接口,它的作用是什么,以及該接口下面比較常用的子實現(xiàn)類有哪些。

明確了之后,接下來我們再來分析一個問題,就是創(chuàng)建容器的時候,到底做了些什么事?

我們都知道BeanFactory是Spring IoC容器最頂層的一個接口,但咱們現(xiàn)在寫的程序用的卻是ApplicationContext這個子接口及其下面的ClassPathXmlApplicationContext子實現(xiàn)類,這是為什么呢?我不說,想必大家也知道,無非就是ApplicationContext屬于非延時加載,也就是說在創(chuàng)建容器對象的時候,就會去實例化bean對象,并存儲在容器里面了。

下面我們就以ClassPathXmlApplicationContext這個容器類來分析一下創(chuàng)建容器的時候,到底都做了些什么事。

首先,查看一下ClassPathXmlApplicationContext類的源碼,如下圖所示,可以看到它里面提供了很多構(gòu)造方法,有無參的,有有參的,反正是有很多,三歲小孩都知道當我們?nèi)?chuàng)建這個類的對象時,必然是要調(diào)用它里面的構(gòu)造方法的。

在這里插入圖片描述

然后,我們就來看一下咱們平時調(diào)用的有參構(gòu)造到底做了哪些事情。你會發(fā)現(xiàn)該有參構(gòu)造又調(diào)用了另外一個有參構(gòu)造,那這個有參構(gòu)造又是誰呢?看,是它!

在這里插入圖片描述

可以看到,在這個構(gòu)造方法里面會先判斷refresh變量是否為true,若為true則調(diào)用refresh方法。很顯然,該refresh變量的值就是true,因為從上一個有參構(gòu)造跳轉(zhuǎn)到該有參構(gòu)造時,第二個參數(shù)傳遞的就是true。既然refresh變量的值為true,那么肯定就會去調(diào)用refresh方法。

那么,refresh方法又做了些什么呢?點擊進入該方法去看看不就得了,你會發(fā)現(xiàn)此時跳轉(zhuǎn)到父類中了,如下圖所示。

在這里插入圖片描述

可以看到,該refresh方法做了很多很多事情,這里我就做一個簡短說明,refresh方法做的事就是加載配置文件并去初始化bean對象,然后將bean對象存儲在容器里面。注意,該方法的具體源代碼,我們就不逐行去分析了,后續(xù)我們自己去實現(xiàn)Spring IoC功能時,再詳細的去說一下它底層的一個實現(xiàn)。

最后,我給大家做個總結(jié)吧!也不知道大家看不看得懂。

ClassPathXmlApplicationContext對bean配置資源的載入是從refresh方法開始的。refresh方法是一個模板方法,規(guī)定了IoC容器的啟動流程,因為有些邏輯是要交給其子類去實現(xiàn)的。那它是如何對bean配置資源進行載入的呢?ClassPathXmlApplicationContext通過調(diào)用其父類AbstractApplicationContext的refresh方法啟動整個IoC容器對bean定義的載入過程。

到此這篇關(guān)于Java 自定義Spring框架與Spring IoC相關(guān)接口分析的文章就介紹到這了,更多相關(guān)Java 自定義Spring框架內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Spring Boot 2.2 正式發(fā)布,大幅性能提升 + Java 13 支持

    Spring Boot 2.2 正式發(fā)布,大幅性能提升 + Java 13 支持

    隨著 Spring Framework 5.2.0 成功發(fā)布之后,Spring Boot 2.2 也緊跟其后,發(fā)布了第一個版本:2.2.0。下面就來一起來看看這個版本都更新了些什么值得我們關(guān)注的內(nèi)容
    2019-10-10
  • AsyncHttpClient的ConnectionSemaphore方法源碼流程解讀

    AsyncHttpClient的ConnectionSemaphore方法源碼流程解讀

    這篇文章主要為大家介紹了AsyncHttpClient的ConnectionSemaphore方法源碼流程解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-12-12
  • Java線程通信詳解

    Java線程通信詳解

    本篇文章主要介紹了Java線程通信問題,線程通信用來保證線程協(xié)調(diào)運行,有需要的朋友可以了解一下。
    2016-10-10
  • 詳細聊聊JDK中的反模式接口常量

    詳細聊聊JDK中的反模式接口常量

    這篇文章主要給大家介紹了關(guān)于JDK中反模式接口常量的相關(guān)資料,文中通過實例代碼介紹的非常詳細,對大家學習或者使用jdk具有一定的參考學習價值,需要的朋友可以參考下
    2022-01-01
  • java圖片滑動驗證(登錄驗證)原理與實現(xiàn)方法詳解

    java圖片滑動驗證(登錄驗證)原理與實現(xiàn)方法詳解

    這篇文章主要介紹了java圖片滑動驗證(登錄驗證)原理與實現(xiàn)方法,結(jié)合實例形式詳細分析了java圖片滑動登錄驗證的相關(guān)原理、實現(xiàn)方法與操作技巧,需要的朋友可以參考下
    2019-09-09
  • cmd編譯運行java程序的方法

    cmd編譯運行java程序的方法

    本文主要介紹了cmd編譯運行java程序的方法,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • Java中數(shù)據(jù)庫常用的兩把鎖之樂觀鎖和悲觀鎖

    Java中數(shù)據(jù)庫常用的兩把鎖之樂觀鎖和悲觀鎖

    這篇文章主要介紹了數(shù)據(jù)庫常用的兩把鎖之樂觀鎖和悲觀鎖,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-07-07
  • 解決IDEA2020.2插件lombok報錯問題(親測有效)

    解決IDEA2020.2插件lombok報錯問題(親測有效)

    這篇文章主要介紹了解決IDEA2020.2插件lombok報錯問題,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-08-08
  • SpringBoot參數(shù)校驗之@Validated的使用詳解

    SpringBoot參數(shù)校驗之@Validated的使用詳解

    這篇文章主要通過示例為大家詳細介紹一下介紹了SpringBoot參數(shù)校驗中@Validated的使用方法,文中的示例代碼講解詳細,需要的可以參考一下
    2022-06-06
  • SpringMVC之@InitBinder注解詳解

    SpringMVC之@InitBinder注解詳解

    這篇文章主要介紹了SpringMVC之@InitBinder注解詳解,springmvc并不是能對所有類型的參數(shù)進行綁定的,如果對日期Date類型參數(shù)進行綁定,就會報錯IllegalStateException錯誤,需要的朋友可以參考下
    2024-01-01

最新評論

岑巩县| 汉寿县| 长汀县| 大余县| 罗甸县| 集贤县| 辉县市| 文成县| 神农架林区| 商城县| 手游| 澄江县| 梅州市| 修文县| 化州市| 新巴尔虎右旗| 马关县| 昌宁县| 西贡区| 海阳市| 伊宁县| 龙山县| 乡宁县| 沈阳市| 中山市| 哈巴河县| 黎平县| 阳原县| 图们市| 石楼县| 元阳县| 静海县| 星座| 通州区| 射阳县| 韶山市| 洛浦县| 宜城市| 得荣县| 河北省| 云阳县|