1. 程式人生 > 實用技巧 >Spring5原始碼系列-02-Spring原始碼整體脈絡

Spring5原始碼系列-02-Spring原始碼整體脈絡

簡介

Spring框架原始碼擁有約108萬行程式碼,如果要把所有的程式碼都看一遍,是需要花費大量時間和精力,而且很容易跟進一個方法繞進去,所以我們需要抓住Spring原始碼主幹原始碼和Spring原始碼對各種設計模式的運用,以及怎麼有條不紊的整合各種框架實現可擴充套件,各種框架是怎麼無縫銜接的織入Spring框架的,比如Spring整合mybatis、nacos是在哪裡織入Spring的等等。

ps:idea 外掛 Statistic 可以統計框架有多少行程式碼

本章主要內容

  1. Spring原始碼的整體脈絡梳理
  2. 什麼是BeanFactory
  3. BeanFactory和ApplicationContext的區別
  4. 圖訴SpringIoc的載入過程

先將類載入成Bean定義,載入Bean定義有一個步驟,首先讀取到我們的配置類,通過我們的配置類,掃描到配置了@Component等註解的類,然後註冊成Bean定義,ApplicationContext可以呼叫BeanFactoryPostProcessor修改Bean定義,呼叫BeanDefinitionRegistryPostProcessor註冊成Bean定義,通過BeanFactory呼叫getBean(),然後會例項化,填充屬性(解析@Autowired、@Value),初始化呼叫各種Aware,呼叫initMethod方法,生產過程中會有很多擴充套件點,最終放在一個Map裡面

  1. 圖訴Bean的生命週期
  2. 圖訴Spring中的擴充套件介面

前置知識

  • Spring框架的使用
  • java程式設計基礎、反射、設計模式、動態代理等

學習資料

概念

IOC 控制反轉:用來解決層層之間的耦合

Spring是一個IOC的容器,容器裡面管理的是各種Bean,IOC控制反轉,是一種設計思想,DI是它的實現。

脈絡

  1. 我們知道IOC管理了很多Bean,那麼怎麼將Bean注入IOC,而成為一個Bean?或者我們怎麼將一個類怎麼變成一個Bean交給IOC管理?

Spring應用的時候一般會

  • 第一步:配置我們的類,不管是xml或者@註解、javaconfig方式配置。
  • 第二步:載入Spring上下文,一般2種方式。xml:new ClassPathXmlApplicationContext("xml") 註解:new AnnotationConfigApplicationContext(Config.class)
  • 第三步:getBean()

通過以上應該我們只知道將類注入到IOC容器中

  1. 當我們的一個類變成一個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檢視該類所有的方法。

由一個工程類傳入不同型別的引數,動態決定應該建立哪一個產品類

  1. 生產獲取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
  1. 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

  1. Bean的生產過程並不是一步到位的,有哪些步驟呢?涉及到Bean的生命週期,有哪些週期?
  • 第一步:例項化,剛才可以看到我們BeanDefinition裡面有引數beanClass,直接通過反射就可以拿到bean
  • 第二步:填充屬性,解析@Autowired、@Value等等
  • 第三步:初始化,可配置一些initMethodName,destroyMethodName
  • 第四步:bean基本已成成形,會put到一個Map裡面,那麼這個Mapkey就是beanname,value存的就是bean的例項,而這個Map就是我們大名鼎鼎的單例池也是一級快取
  • 第五步:getBean()的時候,就是直接在Map裡面獲取例項

在初始化的是時候回回調大量的XXXAware介面

  • BeanNameAware
  • BeanClassLoaderAware
  • BeanFactoryAware
  • EnvironmentAware
  • EmbeddedValueResolverAware
  • ResourceLoaderAware
  • ApplicationEventPublisherAware
  • MessageSourceAware
  • ApplicationContextAware
  • ServletContextAware
  1. Spring例項化的方式有哪些?
  • 反射:@Component等的方式,在例項化的過程,是由Spring控制的
  • 工廠:@Bean標記的方法是工廠方法,工廠可以通過new()來自己控制,比較靈活
  1. 擴充套件點(敲黑板,看重點)

因為這個2個擴充套件節點知識比較多,非常非常非常重要,重要的時說三遍,另寫文章,先眼熟一下類名。

在註冊Bean定義的時候,還可以修改,比如設計師在設計衣櫃的時候,可以修好圖紙,只要還沒有執行getBean()方法,就好像圖紙給了工廠了,但是工廠因為效益好,還沒有來的急做,這時候客戶突然說,我想換個顏色等,然後設計師改好後,就從新發給工廠

Spring提供擴充套件介面,讓我可以對BeanDefinition(bean定義)進行擴充套件,這個介面就是BeanFactoryPostProcessor

除了修改還可以註冊BeanDefinitionRegistryPostProcessor

Spring除了IOC的實現不用擴充套件點,剩下的很多功能都是基於擴充套件點整合的。這就是Spring生態可以做的非常好的原因。

除了Bean定義有擴充套件點以外,Bean的生命週期也有擴充套件點BeanPostPorcessor(Bean的後置處理器),在Bean的生命週期中一共會呼叫9次Bean的後置處理器。

  1. 整體脈絡圖

線上檢視:
https://www.processon.com/view/link/5f606b33e0b34d080d49f0a2