三分鐘深入瞭解Spring底層

張家煦發表於2020-11-29
Pivotal中國研發中心, EMC,VMware和 通用電氣 (GE)的聯合投資
 
說說你對spring的瞭解,是IOC、AOP嗎?
spring中有很多專案,IOC-AOP是spring framework中的核心技術的一部分
一個springbean一定是一個物件
spring bean---object
經過一個完整的生命週期
bean的生命週期:
    先明確兩個概念spring bean和物件
1、spring bean ——受spring容器管理的物件,可能經過了完整的spring bean生命週期(為什麼是可能?難道還有bean是沒有經過bean生命週期的?答案是有的,具體我們後面文章分析),最終存在spring容器當中;一個bean一定是個物件
2、物件 ——任何符合java語法規則例項化出來的物件,但是一個物件並不一定是spring bean;
 
所謂的bean的生命週期就是磁碟上的類通過spring掃描,然後例項化,跟著初始化,繼而放到容器當中的過程;
 
spring容器初始化bean的大概過程
1:例項化一個ApplicationContext的物件;
2:呼叫bean工廠後置處理器完成掃描;
3:迴圈解析掃描出來的類資訊;
4:例項化一個BeanDefinition物件來儲存解析出來的資訊;
5:把例項化好的beanDefinition物件put到 beanDefinitionMap 當中快取起來,以便後面例項化bean;
6:再次呼叫bean工廠後置處理器;
7:當然spring還會幹很多事情,比如國際化,比如註冊BeanPostProcessor等等,如果我們只關心如何例項化一個bean的話那麼這一步就是spring呼叫 finishBeanFactoryInitialization 方法來例項化單例的bean,例項化之前spring要做驗證,需要遍歷所有掃描出來的類,依次判斷這個bean是否Lazy,是否prototype,是否abstract等等;
8:如果驗證完成spring在例項化一個bean之前需要推斷構造方法,因為spring例項化物件是通過構造方法反射,故而需要知道用哪個構造方法;
9:推斷完構造方法之後spring呼叫構造方法反射例項化一個 物件 ;注意我這裡說的是物件、物件、物件;這個時候物件已經例項化出來了,但是並不是一個完整的bean,最簡單的體現是這個時候例項化出來的物件屬性是沒有注入,所以不是一個完整的bean;
10:spring處理合並後的beanDefinition(合併?是spring當中非常重要的一塊內容,後面的文章我會分析);
11:判斷是否支援迴圈依賴,如果支援則提前把一個工廠存入singletonFactories——map;
12:判斷是否需要完成屬性注入
13:如果需要完成屬性注入,則開始注入屬性
14:判斷bean的型別回撥Aware介面
15:呼叫生命週期回撥方法
16:如果需要代理則完成代理
17:put到單例池——bean完成——存在spring容器當中
 
 
 
什麼是spring容器?是一個非常抽象的概念
 spring的各個元件組合在一起稱為spring容器,比如spring單例池、springBean工廠、spring掃描器、spring讀取器、spring後置處理器
 
spring後置處理器:
spring IOC的原始碼分析
 
xml based \  java based (主流)  \Annotation
不僅僅            
 
spring5的原始碼是用gradle構建的
 
需要匯入的依賴
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.8.RELEASE</version>
</dependency>

因為有些依賴maven已經幫我們匯入了

 
springbean的生命週期===spring如何把一個bean產生的和把一個bean銷燬的
 
初始化spring上下文  容器 環境 一摸一樣
public class Test {
    public static void main(String[] args) {
//基於XML
//        ClassPathXMLApplicationContext
//            classPathXMLApplicationContext = new ClassPathXMLApplicationContext("spring.xml");
        AnnotationConfigApplicationContext

//基於Java
                annotationConfigApplicationContext
                =new AnnotationConfigApplicationContext(Appconfig.class);
        System.out.println(annotationConfigApplicationContext.getBean(Test.class));
    }

}

解析上面程式碼:會先呼叫ClassPathXMLApplicationContext的構造方法,此時會呼叫父類的構造方法(無參)this.beanFactory = new DefaultListableBeanFactory();(能夠產生bean的)

spring容器當中存在一個工廠--生產bean的
那什麼是bean?---程式碼級別就是DefaultListableBeanFactory
DefaultListableBeanFactory---原料beanDefinitMap(最重要)
大體: annotationConfigApplicationContext
                =new AnnotationConfigApplicationContext(Appconfig.class);它會解析
Appconfig類,該類掃描,掃描到很多類之後進行for迴圈,它會把這個類的資訊:名字、作用域、需不需要懶載入,把這些封裝到 genericBeanDefinition物件中,然後把這個物件put到map中。然後遍歷map,初始化物件genericBeanDefinition.getBeanClass().newInstance()
首先把類檔案載入到jvm
  1. spring容器啟動,通過bean工廠的後置處理器( ConfigurationClassPostProcessor)完成掃描(讀取類的資訊)。---讀取到的類資訊會放到BeanDefinition類中,原因:例項化一個bean除了.class檔案中的資訊還要具備 scope,lazy,dependsOn等等資訊需要儲存
  2. 例項化一個BeanDefinition的物件,呼叫各種set方法儲存資訊。每掃描到一個符合規則的類,spring都會例項化一個BeanDefinition物件,然後根據類的類名生成一個bean的名字,當然你可以提供自己的名字生成器覆蓋spring內建的規則
  3. 然後spring會把這個beanDefinition物件和生成的beanName放到一個map當中,key=beanName,value=beanDefinition物件
  4. BeanFactoryPostProcessor在容器例項化任何其他bean之前讀取配置後設資料,並可以根據需要進行修改,例如:可以把bean的scope從singleton改為prototype。
spring產生一個be'an跟類產生的beanDefinition物件有關係,跟類沒有關係
 
public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {}
 
public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {}
 
public GenericApplicationContext() {
    this.customClassLoader = false;
    this.refreshed = new AtomicBoolean();
    this.beanFactory = new DefaultListableBeanFactory();
}
this.beanFactory 說明spring包含一個工廠,它的這個工廠具體就是new DefaultListableBeanFactory()  ----beanDefinitMap(相當於原料)
正常情況:遍歷map,new?反射?序列化?克隆?都不是
new出來放到spring單例池中
非正常情況:程式碼級別:所有繼承ApplicationContext類的都是容器
 
spring產生一個bean跟map中beanDefinite物件有關係,跟這個類沒有關係
AnnotationConfigApplicationContext ac =new AnnotationConfigApplicationContext(Appconfig.class);
 
掃描包下面的類
當類過多的時候,他會進行for迴圈
 
refresh() 
 
類變成beanDefinition,放到map中
上述這一步怎麼做的,如下
map中的物件例項化到單例池中
 
FactoryBean  BeanFactory區別
 
FactoryBean 普通Bean 區別:普通Bean會放到單例池中
 
迴圈依賴---spring如何解決迴圈依賴的--兩次getSingleton
 
Sring後置處理器---生命週期
 
 
 

相關文章