第二章 IOC + AOP 底層原理


《精通Spring4.x 企業應用開發實戰》讀書筆記

一、概念

IOC:

  • 假設B類調用了A類,那么A類的對象的創建是由B類來實現;
  • IOC是指將A對象的創建由容器來完成,並且將創建好的對象注入到B類中供B類對象使用

好處:

  • 減少對象的創建工作
  • 解耦B類與A類對象的創建過程

 

二、Resource接口

  • “classpath:”:只會在第一個加載的com.xxx包的類路徑下查找;
  • “classpath*:”:會掃描所有類路徑下的com.xxx包中的查找

 

三、Bean工廠

  • BeanFactory:
    • 容器啟動時,將配置文件中的Bean裝載到容器(hashMap<beanName, BeanDefinition>)
    • 配置文件中的Bean的初始化是在第一次調用時進行 - “懶實例化”
    • 緩存單例Bean,第二次調用時獲取bean從IOC容器緩存中獲取(hashMap<beanName, Bean>)
  • ApplicationContext:在BeanFactory的基礎上,增加了“國際化支持”和“事件體系”
    • 事件體系:
      • ApplicationEventPublisher:發布事件,實際上會調用ApplicationEventMulticaster實例來發布。
      • ApplicationEventMulticaster:提供了監聽器注冊表,保存所有的監聽器;發布事件,並通知相應的監聽器進行相應操作
    • 上下文初始化時,創建所有單例Bean - “急切實例化”  

 

四、Spring啟動流程

1、初始化BeanFactory

  • 創建BeanFactory實例
  • 將配置文件的信息裝入BeanDefinitionRegistry(Bean定義注冊表)中
    • 使用ResourceLoader將配置文件裝載為Resource對象
    • 使用BeanDefinitionReader解析配置信息:將每一個<bean>解析為一個BeanDefinition對象,然后存儲到BeanDefinitionRegistry中

2、調用BeanFactoryPostProcessor

  • 根據反射機制從BeanDefinitionRegistry中找出所有實現了BeanFactoryPostProcessor接口的Bean,並調用其postProcessBeanFactory()接口方法,實際上完成的工作主要是:- 可定制點
    • 對使用占位符的<bean>進行解析,得到最終的配置值,即將半成品的BeanDefinition轉化為完全體的BeanDefinition對象
    • 根據反射機制從BeanDefinitionRegistry中找出所有實現了java.beans.PropertyEditor接口的Bean,並自動將他們注冊到ProperEditorRegistry中

3、注冊BeanPostProcessor

  • 根據反射機制從BeanDefinitionRegistry中找出所有實現了BeanPostProcessor接口的Bean,並將他們注冊到BeanPostProcessor的注冊表中 - 可定制點
  • 重要點:Aop、動態代理都是基於這個實現的

4、初始化國際化信息資源

5、初始化應用上下文事件廣播器 - 事件

6、初始化特殊的Bean:鈎子方法 - 可定制點

  • springboot在這一步創建了TomcatEmbeddedServletContainer,即內嵌的tomcat容器

7、注冊事件監聽器到ApplicationEventMulticaster的監聽器注冊表中

8、初始化所有的單例Bean,使用懶加載的除外;初始化Bean后,放入spring容器的緩沖池(hashMap<beanName, Bean>

  • 取出BeanDefinitionRegistry中的BeanDefinition對象,使用InstantiationStrategy實例化Bean;
  • 使用BeanWrapper結合Bean實例和ProperEditorRegistry對Bean進行屬性注入操作;
  • 使用3中注冊好的BeanPostProcessor對已經完成屬性設置的Bean進行后續加工,裝配置出准備就緒的Bean。
  • 初始化 - init-method
  • 放入緩沖池(單例),多例交給調用者(后續該Bean的生命周期由垃圾回收來定了)

9、發布上下文刷新事件 :創建上下文刷新事件,事件廣播器負責將這些事件廣播到每個注冊的事件監聽器中 - 事件

 

類比:springboot啟動核心流程

1、創建SpringApplication對象

  • 判斷是否是web環境
  • 創建並初始化ApplicationInitializer列表
  • 創建並初始化ApplicationListener列表
  • 初始化主類mainApplicationClass

2、執行run方法

  • 獲取SpringApplicationRunListeners
    • 創建了EventPublishingRunListener實例
    • 創建事件廣播器SimpleApplicationEventMulticaster實例
    • 將之前初始化好的ApplicationListener列表全部注冊到事件廣播器的事件注冊表中
  • 創建並初始化ConfigurableEnvironment
    • 創建一個MutablePropertySources復合屬性源
    • 構造包含server.port等啟動參數的屬性源,並設置到復合屬性源的首部,優先級最高
    • 讀取application.properties文件內容,並構造為一個name為“applicationConfigurationProperties”的屬性源,並設置到復合屬性源的尾部
  • 創建ConfigurableApplicationContext
  • 准備ConfigurableApplicationContext
    • 執行初始化好了的ApplicationInitializer列表
  • 刷新ConfigurableApplicationContext
    • 將spring啟動流程執行了一遍
  • 容器刷新后動作
  • SpringApplicationRunListeners發布finish事件

 

五、BeanFactory中Bean生命周期

大致來講:

  • 創建Bean實例
  • 設置屬性值以及對其他Bean的引用
  • 初始化 - init-method
  • 放入緩沖池(單例),多例交給調用者(后續該Bean的生命周期由垃圾回收來定了)
  • 銷毀Bean - destroy - method

 

 

 六、AOP

兩種代理:

  • JDK:基於接口
    • 原理:動態代理 + 反射
    • 定義一個類XxHandler,實現InvocationHandler接口,里邊包含真實對象的實例(實際上是一個Object,具體真實對象在運行期賦值給Object),並使用反射調用真實對象的指定方法
    • 使用Proxy.newProxyInstance(ClassLoader, interfaces, InvocationHandler)創建代理對象,之后調用相應的真實對象的方法即可。
      • 由於該方法的第二個對象是interface,所以JDK只能基於接口實現動態代理。
  • CGLib:基於類
    • 原理:動態生成字節碼技術,即為將要攔截的類動態生成子類,然后在子類中攔截所有父類的調用並順勢織入橫切邏輯。
    • 由於是創建子類,所以不能代理目標類中的private和final方法。

比較:

  • CGLib創建代理對象花費的時間長於JDK,因為要動態生成子類
  • CGLib創建好的代理對象的性能由於JDK


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM