核心

BeanDefinition

容器中的每一個(gè) bean 都會(huì)有一個(gè)對(duì)應(yīng)的 BeanDefinition 實(shí)例,該實(shí)例負(fù)責(zé)保存bean對(duì)象的所有必要信息,包括 bean 對(duì)象的 class 類(lèi)型、是否是抽象類(lèi)、構(gòu)造方法和參數(shù)、其它屬性等等。

BeanDefinitionRegistry和 BeanFactory就是菜譜(記錄這道菜怎么做出來(lái)的)

BeanDefinitionRegistry 抽象出 bean 的注冊(cè)邏輯,而 BeanFactory 則抽象出了 bean 的管理邏輯,而各個(gè) BeanFactory 的實(shí)現(xiàn)類(lèi)就具體承擔(dān)了 bean 的注冊(cè)以及管理工作

DefaultListableBeanFactory

實(shí)現(xiàn)BeanFactory接口 ,它同時(shí)也實(shí)現(xiàn)了 BeanDefinitionRegistry 接口

IOC容器的工作流程

  1. 容器啟動(dòng)階段
    容器啟動(dòng)時(shí),會(huì)通過(guò)某種途徑加載 ConfigurationMetaData(xml的配置文件)。除了代碼方式比較直接外,在大部分情況下,容器需要依賴(lài)某些工具類(lèi),比如: BeanDefinitionReader,BeanDefinitionReader 會(huì)對(duì)加載的 ConfigurationMetaData(xml的配置文件)進(jìn)行解析和分析,并將分析后的信息組裝為相應(yīng)的 BeanDefinition,最后把這些保存了 bean 定義的 BeanDefinition,注冊(cè)到相應(yīng)的 BeanDefinitionRegistry,這樣容器的啟動(dòng)工作就完成了。
  2. Bean的實(shí)例化階段
    經(jīng)過(guò)第一階段,所有 bean 定義都通過(guò) BeanDefinition 的方式注冊(cè)到 BeanDefinitionRegistry 中,當(dāng)某個(gè)請(qǐng)求通過(guò)容器的 getBean 方法請(qǐng)求某個(gè)對(duì)象,或者因?yàn)橐蕾?lài)關(guān)系容器需要隱式的調(diào)用 getBean 時(shí),就會(huì)觸發(fā)第二階段的活動(dòng):容器會(huì)首先檢查所請(qǐng)求的對(duì)象之前是否已經(jīng)實(shí)例化完成。如果沒(méi)有,則會(huì)根據(jù)注冊(cè)的 BeanDefinition 所提供的信息實(shí)例化被請(qǐng)求對(duì)象,并為其注入依賴(lài)。當(dāng)該對(duì)象裝配完畢后,容器會(huì)立即將其返回給請(qǐng)求方法使用。
    BeanFactory 只是 Spring IoC 容器的一種實(shí)現(xiàn),如果沒(méi)有特殊指定,它采用采用延遲初始化策略:只有當(dāng)訪問(wèn)容器中的某個(gè)對(duì)象時(shí),才對(duì)該對(duì)象進(jìn)行初始化和依賴(lài)注入操作。而在實(shí)際場(chǎng)景下,我們更多的使用另外一種類(lèi)型的容器: ApplicationContext,它構(gòu)建在 BeanFactory 之上,屬于更高級(jí)的容器,除了具有 BeanFactory 的所有能力之外,還提供對(duì)事件監(jiān)聽(tīng)機(jī)制以及國(guó)際化的支持等。它管理的 bean,在容器啟動(dòng)時(shí)全部完成初始化和依賴(lài)注入操作。(?? BeanFactory在被請(qǐng)求getBean要獲取bean時(shí)才實(shí)例化,而如果說(shuō)BeanFactory是Spring的心臟,那么ApplicationContext就是完整的軀體了,ApplicationContext由BeanFactory派生而來(lái),比它強(qiáng)大)

JavaConfig (@Configuration @Bean)

上面我們提到bean的定義和相互間是用xml描述的,因?yàn)楫a(chǎn)生了許多的xml文件因此人們對(duì)它不滿(mǎn),所以完善了用Annotation來(lái)注冊(cè)bean就是我們所見(jiàn)的@注釋

@ComponentScan

注解用于導(dǎo)入配置類(lèi),比如配置類(lèi)中的bean依賴(lài)于另一個(gè)別的類(lèi)的bean,那么就可以借助@import把依賴(lài)的那個(gè)bean引進(jìn)配置類(lèi)
通過(guò) basePackages等屬性來(lái)指定 @ComponentScan自動(dòng)掃描的范圍,如果不指定,默認(rèn)從聲明 @ComponentScan所在類(lèi)的 package進(jìn)行掃描。正因?yàn)槿绱?,SpringBoot的啟動(dòng)類(lèi)都默認(rèn)在 src/main/java下

@Import

用于導(dǎo)入配置類(lèi),比如配置類(lèi)中的bean依賴(lài)于另一個(gè)別的類(lèi)的bean,那么就可以借助@import把依賴(lài)的那個(gè)bean引進(jìn)配置類(lèi)

例子:

@Configuration
public class MoonBookConfiguration {
    @Bean
    public BookService bookService() {
        return new BookServiceImpl();
    }
}

現(xiàn)在有另外一個(gè)配置類(lèi),比如: MoonUserConfiguration,這個(gè)配置類(lèi)中有一個(gè)bean依賴(lài)于 MoonBookConfiguration中的bookService,如何將這兩個(gè)bean組合在一起?借助 @Import即可:

@Configuration
// 可以同時(shí)導(dǎo)入多個(gè)配置類(lèi),比如:@Import({A.class,B.class})
@Import(MoonBookConfiguration.class)
public class MoonUserConfiguration {
    @Bean
    public UserService userService(BookService bookService) {
        return new BookServiceImpl(bookService);
    }
}

在4.2之前, @Import注解只支持導(dǎo)入配置類(lèi),但是在4.2之后,它支持導(dǎo)入普通類(lèi),并將這個(gè)類(lèi)作為一個(gè)bean的定義注冊(cè)到IOC容器中

@Conditional

表示在滿(mǎn)足某種條件后才初始化一個(gè)bean或者啟用某些配置

@ConfigurationProperties與@EnableConfigurationProperties

當(dāng)某些屬性的值需要配置的時(shí)候,我們一般會(huì)在 application.properties文件中新建配置項(xiàng),然后在bean中使用 @Value注解來(lái)獲取配置的值。
使用 @Value注解注入的屬性通常都比較簡(jiǎn)單,如果同一個(gè)配置在多個(gè)地方使用,也存在不方便維護(hù)的問(wèn)題(考慮下,如果有幾十個(gè)地方在使用某個(gè)配置,而現(xiàn)在你想改下名字,你改怎么做?)。對(duì)于更為復(fù)雜的配置,Spring Boot提供了更優(yōu)雅的實(shí)現(xiàn)方式,那就是 @ConfigurationProperties注解。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容