BeanDefinition
容器中的每一個 bean 都會有一個對應的 BeanDefinition 實例,該實例負責保存bean對象的所有必要信息,包括 bean 對象的 class 類型、是否是抽象類炼邀、構造方法和參數(shù)槽片、其它屬性等等。
BeanDefinitionRegistry和 BeanFactory就是菜譜(記錄這道菜怎么做出來的)
BeanDefinitionRegistry 抽象出 bean 的注冊邏輯普筹,而 BeanFactory 則抽象出了 bean 的管理邏輯,而各個 BeanFactory 的實現(xiàn)類就具體承擔了 bean 的注冊以及管理工作
DefaultListableBeanFactory
實現(xiàn)BeanFactory接口 隘马,它同時也實現(xiàn)了 BeanDefinitionRegistry 接口
IOC容器的工作流程
- 容器啟動階段
容器啟動時太防,會通過某種途徑加載 ConfigurationMetaData(xml的配置文件)。除了代碼方式比較直接外酸员,在大部分情況下蜒车,容器需要依賴某些工具類,比如: BeanDefinitionReader幔嗦,BeanDefinitionReader 會對加載的 ConfigurationMetaData(xml的配置文件)進行解析和分析酿愧,并將分析后的信息組裝為相應的 BeanDefinition,最后把這些保存了 bean 定義的 BeanDefinition邀泉,注冊到相應的 BeanDefinitionRegistry嬉挡,這樣容器的啟動工作就完成了钝鸽。 - Bean的實例化階段
經過第一階段,所有 bean 定義都通過 BeanDefinition 的方式注冊到 BeanDefinitionRegistry 中庞钢,當某個請求通過容器的 getBean 方法請求某個對象拔恰,或者因為依賴關系容器需要隱式的調用 getBean 時,就會觸發(fā)第二階段的活動:容器會首先檢查所請求的對象之前是否已經實例化完成基括。如果沒有颜懊,則會根據(jù)注冊的 BeanDefinition 所提供的信息實例化被請求對象,并為其注入依賴风皿。當該對象裝配完畢后河爹,容器會立即將其返回給請求方法使用。
BeanFactory 只是 Spring IoC 容器的一種實現(xiàn)桐款,如果沒有特殊指定咸这,它采用采用延遲初始化策略:只有當訪問容器中的某個對象時,才對該對象進行初始化和依賴注入操作魔眨。而在實際場景下炊苫,我們更多的使用另外一種類型的容器: ApplicationContext,它構建在 BeanFactory 之上冰沙,屬于更高級的容器侨艾,除了具有 BeanFactory 的所有能力之外,還提供對事件監(jiān)聽機制以及國際化的支持等拓挥。它管理的 bean唠梨,在容器啟動時全部完成初始化和依賴注入操作。(?? BeanFactory在被請求getBean要獲取bean時才實例化侥啤,而如果說BeanFactory是Spring的心臟当叭,那么ApplicationContext就是完整的軀體了,ApplicationContext由BeanFactory派生而來盖灸,比它強大)
JavaConfig (@Configuration @Bean)
上面我們提到bean的定義和相互間是用xml描述的蚁鳖,因為產生了許多的xml文件因此人們對它不滿,所以完善了用Annotation來注冊bean就是我們所見的@注釋
@ComponentScan
注解用于導入配置類赁炎,比如配置類中的bean依賴于另一個別的類的bean醉箕,那么就可以借助@import把依賴的那個bean引進配置類
通過 basePackages等屬性來指定 @ComponentScan自動掃描的范圍,如果不指定徙垫,默認從聲明 @ComponentScan所在類的 package進行掃描讥裤。正因為如此,SpringBoot的啟動類都默認在 src/main/java下
@Import
用于導入配置類姻报,比如配置類中的bean依賴于另一個別的類的bean己英,那么就可以借助@import把依賴的那個bean引進配置類
例子:
@Configuration
public class MoonBookConfiguration {
@Bean
public BookService bookService() {
return new BookServiceImpl();
}
}
現(xiàn)在有另外一個配置類,比如: MoonUserConfiguration吴旋,這個配置類中有一個bean依賴于 MoonBookConfiguration中的bookService损肛,如何將這兩個bean組合在一起厢破?借助 @Import即可:
@Configuration
// 可以同時導入多個配置類,比如:@Import({A.class,B.class})
@Import(MoonBookConfiguration.class)
public class MoonUserConfiguration {
@Bean
public UserService userService(BookService bookService) {
return new BookServiceImpl(bookService);
}
}
在4.2之前治拿, @Import注解只支持導入配置類摩泪,但是在4.2之后,它支持導入普通類忍啤,并將這個類作為一個bean的定義注冊到IOC容器中
@Conditional
表示在滿足某種條件后才初始化一個bean或者啟用某些配置
@ConfigurationProperties與@EnableConfigurationProperties
當某些屬性的值需要配置的時候,我們一般會在 application.properties文件中新建配置項仙辟,然后在bean中使用 @Value注解來獲取配置的值同波。
使用 @Value注解注入的屬性通常都比較簡單,如果同一個配置在多個地方使用叠国,也存在不方便維護的問題(考慮下未檩,如果有幾十個地方在使用某個配置,而現(xiàn)在你想改下名字粟焊,你改怎么做冤狡?)。對于更為復雜的配置项棠,Spring Boot提供了更優(yōu)雅的實現(xiàn)方式悲雳,那就是 @ConfigurationProperties注解。