Spring5原始碼系列-02-Spring原始碼整體脈絡
簡介
Spring框架原始碼擁有約108萬行程式碼,如果要把所有的程式碼都看一遍,是需要花費大量時間和精力,而且很容易跟進一個方法繞進去,所以我們需要抓住Spring原始碼主幹原始碼和Spring原始碼對各種設計模式的運用,以及怎麼有條不紊的整合各種框架實現可擴充套件,各種框架是怎麼無縫銜接的織入Spring框架的,比如Spring整合mybatis、nacos是在哪裡織入Spring的等等。
ps:idea 外掛 Statistic 可以統計框架有多少行程式碼
本章主要內容
- Spring原始碼的整體脈絡梳理
- 什麼是BeanFactory
- BeanFactory和ApplicationContext的區別
- 圖訴SpringIoc的載入過程
先將類載入成Bean定義,載入Bean定義有一個步驟,首先讀取到我們的配置類,通過我們的配置類,掃描到配置了@Component等註解的類,然後註冊成Bean定義,ApplicationContext可以呼叫BeanFactoryPostProcessor修改Bean定義,呼叫BeanDefinitionRegistryPostProcessor註冊成Bean定義,通過BeanFactory呼叫getBean(),然後會例項化,填充屬性(解析@Autowired、@Value),初始化呼叫各種Aware,呼叫initMethod方法,生產過程中會有很多擴充套件點,最終放在一個Map裡面
- 圖訴Bean的生命週期
- 圖訴Spring中的擴充套件介面
前置知識
- Spring框架的使用
- java程式設計基礎、反射、設計模式、動態代理等
學習資料
概念
IOC 控制反轉:用來解決層層之間的耦合
Spring是一個IOC的容器,容器裡面管理的是各種Bean,IOC控制反轉,是一種設計思想,DI是它的實現。
脈絡
- 我們知道IOC管理了很多Bean,那麼怎麼將Bean注入IOC,而成為一個Bean?或者我們怎麼將一個類怎麼變成一個Bean交給IOC管理?
Spring應用的時候一般會
- 第一步:配置我們的類,不管是xml或者@註解、javaconfig方式配置。
- 第二步:載入Spring上下文,一般2種方式。xml:new ClassPathXmlApplicationContext("xml") 註解:new AnnotationConfigApplicationContext(Config.class)
- 第三步:getBean()
通過以上應該我們只知道將類注入到IOC容器中
- 當我們的一個類變成一個Bean的最核心的一個類是什麼?
是BeanFactory
BeanFactory是Spring頂層核心介面,使用了簡單工廠模式(可參考前面提供的設計模式簡單學習一下),負責生產bean。
以下面簡單demo為了例檢視:
@Configuration
@ComponentScan
public class MainApp {
public static void main(String[] args) {
ApplicationContext context=new AnnotationConfigApplicationContext(MainApp.class);
UserServiceImpl bean = context.getBean("userServiceImpl",UserServiceImpl.class);
bean.sayHi();
}
getBean()方法
@Override
public <T> T getBean(Class<T> requiredType) throws BeansException {
assertBeanFactoryActive();
return getBeanFactory().getBean(requiredType);
}
Spring上下文(AnnotationConfigApplicationContext)不生產bean,通知getBeanFactory()
去生產Bean,getBean()
方法即可以獲取Bean,也可以生產Bean,這個方法有2個作用。
檢視BeanFactory
原始碼,以idea為例,雙擊shift
,搜尋BeanFactory
找到該類,快捷鍵 Ctrl + F12
檢視該類所有的方法。
由一個工程類傳入不同型別的引數,動態決定應該建立哪一個產品類
- 生產獲取Bean的工廠有了,那麼我怎麼讀取到Bean呢?
我們有可能是xml配置的,有可能是註解配置的,這樣就需要一個 統一的抽象的 讀取後存放至一個介面類裡面,那個這個統一的介面是什麼呢?
BeanFactory只負責生產獲取Bean,再負責讀取就有些不太符合我們單一指責原則。
所以這個統一的介面就是BeanDefinition
,Spring頂層核心介面,封裝了生產Bean的一切原材料。具體哪些原材料,請看下面提供的資訊。
BeanDefinition介面的核心之類AbstractBeanDefinition
或者訪問:http://processon.com/chart_image/5f79449de401fd06fd76ff5e.png
下面以一個生活的例子描述下這個幾個的關係:
比如我們買新房子要裝修,比如需要定製一個衣櫃和櫥櫃
- 第一步:需要找到一個定製衣櫃的
衣櫃店
,定製衣櫃
。衣櫃店不會生產定製衣櫃,而是通知一個工廠
來生產定製衣櫃 - 第二步:衣櫃店會有一個
設計師
,按照你的要求設計出一個圖紙
,比如:會有顏色款式
等的要求,衣櫃店負責人通知工廠按照圖紙製作一個衣櫃。 - 第三步:工廠按照圖紙要求製作衣櫃,製作好後,送到衣櫃店,等待
你
來取走。
如果再定製櫥櫃,跟上面步驟差不多
- 衣櫃店的角色就是
ClassPathXmlApplicationContext
- 櫥櫃店的角色就是
AnnotationConfigApplicationContext
- 而你就是 一個帶有
@Component
的class - 工廠就是
BeanFactory
- 顏色和款式就是
@Lazy或者@Scope
等 - 衣櫃就是
Bean
- 圖紙就是
BeanDefinition
- 設計師就是
BeanDefinitionRegistry
衣櫃店肯定不止一個設計師,也有銷售推廣
等,推廣人員去市場尋找在潛在客戶
,比如推廣人員在杭州市西湖區某個小區發傳單推廣,小區一共有1000個,1000個人就是潛在客戶
推廣人員挨家挨戶的介紹產品,但是最終只有10個人買了衣櫃,這10個客戶就是真實客戶
。
- 推廣人員這個角色就是
BeanDefinitionReader
- 市場就是
xml
和配置類
,這裡可以看做上面例子的杭州市西湖區某小區。比如:配置類配置了org.spring.study
這個包,這個包下有1000個類,而只有10個類配置了@Component
、@Service
等註解 - 潛在客戶就是
BeanDefinitionSacnner
- 真實客戶就是
bean
- BeanFactory和Application有什麼區別?
類結構圖:
共同:都有生產bean的能力
區別:
Feature | BeanFactory | ApplicationContext |
---|---|---|
Bean Bean例項化/裝配 | Yes | Yes |
整合的生命週期管理 | No | Yes |
自動註冊 BeanPostProcessor | No | Yes |
自動註冊 BeanFactoryPostProcessor | No | Yes |
便利的 MessageSource 訪問 (國際化) | No | Yes |
內建ApplicationEvent 釋出機制 | No | Yes |
Spring中文文件:
https://github.com/DocsHome/spring-docs/blob/master/pages/core/overview.md
- Bean的生產過程並不是一步到位的,有哪些步驟呢?涉及到Bean的生命週期,有哪些週期?
- 第一步:例項化,剛才可以看到我們
BeanDefinition
裡面有引數beanClass
,直接通過反射
就可以拿到bean
- 第二步:填充屬性,解析@Autowired、@Value等等
- 第三步:初始化,可配置一些
initMethodName
,destroyMethodName
等 - 第四步:bean基本已成成形,會
put
到一個Map
裡面,那麼這個Map
的key
就是beanname,value
存的就是bean的例項,而這個Map
就是我們大名鼎鼎的單例池
也是一級快取
- 第五步:getBean()的時候,就是直接在
Map
裡面獲取例項
在初始化的是時候回回調大量的XXXAware介面
- BeanNameAware
- BeanClassLoaderAware
- BeanFactoryAware
- EnvironmentAware
- EmbeddedValueResolverAware
- ResourceLoaderAware
- ApplicationEventPublisherAware
- MessageSourceAware
- ApplicationContextAware
- ServletContextAware
- Spring例項化的方式有哪些?
- 反射:@Component等的方式,在例項化的過程,是由Spring控制的
- 工廠:@Bean標記的方法是工廠方法,工廠可以通過new()來自己控制,比較靈活
- 擴充套件點(敲黑板,看重點)
因為這個2個擴充套件節點知識比較多,非常非常非常重要,重要的時說三遍,另寫文章,先眼熟一下類名。
在註冊Bean定義的時候,還可以修改,比如設計師在設計衣櫃的時候,可以修好圖紙,只要還沒有執行getBean()方法,就好像圖紙給了工廠了,但是工廠因為效益好,還沒有來的急做,這時候客戶突然說,我想換個顏色等,然後設計師改好後,就從新發給工廠
Spring提供擴充套件介面,讓我可以對BeanDefinition
(bean定義)進行擴充套件,這個介面就是BeanFactoryPostProcessor
除了修改還可以註冊BeanDefinitionRegistryPostProcessor
Spring除了IOC的實現不用擴充套件點,剩下的很多功能都是基於擴充套件點整合的。這就是Spring生態可以做的非常好的原因。
除了Bean定義有擴充套件點以外,Bean的生命週期也有擴充套件點BeanPostPorcessor
(Bean的後置處理器),在Bean的生命週期中一共會呼叫9次Bean的後置處理器。
- 整體脈絡圖
線上檢視:
https://www.processon.com/view/link/5f606b33e0b34d080d49f0a2