《精通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