spring 相關

antor發表於2024-08-11

1. 對spring 的理解

spring 是一個廣泛應用於企業級java 開發的強大框架, 為開發複雜的應用程式提供了全面而高效的解決方案
1. spring 的核心是控制反轉+依賴注入, 即IOC 和DI, 這意味著物件的建立和管理不再由開發者直接負責, 而是可以交由Spring 容器來處理, 透過配置檔案或者註解的形式, 可以清晰的定義物件之間的依賴關係, 使得程式碼更加模組化,可維護和可測試
2. spring 還提供了面向切面(AOP)程式設計的支援, 這使得我們能夠將橫切關注點(如記錄日誌、事務管理、許可權檢查等) 從業務邏輯中分離出來, 以一種更加模組化和可重用的方式進行處理
  比如, 對於spring 事務, 可以透過AOP定義一個切面, 在方法執行前後自動處理事務的開始和提交/回滾, 而無需在每個業務方法中重複編寫事務相關程式碼
3. 在資料訪問方面, spring 整合了多種資料訪問技術, 如JDBC、MyBatis、Hibernate等, 並提供了統一的模版和資源管理, 簡化了資料操作的複雜性
4. spring 的web 模組為構建web 應用提供了強大的支援, 包括控制器的定義、請求處理、檢視解析等, 與其他前端的整合也非常方便
5. spring Security 則為應用提供了全面的安全管理功能, 包括使用者認證、授權、加密等
6. 對於分散式系統, spring cloud 基於spring 框架, 提供了一系列的工具和元件, 用於實現服務註冊與發現、配置管理、負載均衡、斷路器等微服務架構的關鍵功能
7. 在實際專案開發中, spring 大大提高了開發效率,減少了程式碼的冗餘,增強了系統的可擴充套件性和可維護性

spring6.0 提供了AOT的支援

2. 對IOC的理解

Spring 的IOC 是一種設計模式,核心思想是將物件的建立、組裝和管理過程交給框架來完成,而不是由應用程式直接控制。
這種模式透過將應用程式的控制權交給框架來提高應用程式的可擴充套件性、靈活性和可維護性

Bean 的定義:
基於XML 的方式以及基於配置類的方式, @Component 註解
Bean 的發現
@Resources @Autowired 構造器等

3. IOC 的原理

本質上是java反射+xml 解析
IOC 本身是針對bean 的管理
bean 的定義
bean 的載入 

IOC 是spring 框架的核心概念之一, 從根本上改變了物件建立和管理的方式, 傳統模式中, 物件之間的依賴關係由物件自身來建立和維護, 而在IOC理念中, 這種控制被反轉了,
物件的建立和依賴關係,不再由物件自身負責,而是交給一個專門的容器, 即IOC容器, IOC 容器負責建立物件、配置物件屬性,並將依賴的物件注入到需要他們的物件中
在IOC模式下,依賴物件可以透過配置(XML配置檔案或者註解等方式) 來進行建立
這樣做,首先降低了物件之間的耦合度, 物件不在關心依賴物件的建立細節, 只需要關注自身的業務邏輯.
其次 使得程式碼更容易測試, 可以更方便的為物件注入模擬的依賴物件進行單元測試,同時IOC容器還可以集中管理物件的生命週期, 實現資源的最佳化和共享

3.1 bean 的定義

在spring 中, bean 是一個被spring 容器管理的物件, 
bean 的定義通常包含了物件的各種資訊, 如物件的型別,屬性值、依賴關係、作用域等等
bean 可以透過 xml 配置、java 註解 如: @Component 及其派生註解 、java 配置類 等方式進行定義
bean 的定義還可以包含屬性的設定、建構函式引數的注入、依賴物件的注入等配置,以滿足不同的需求

3.2 bean的載入

在spring 中,對於以配置類形式進行的Bean 載入,會產生對應的BeanDefinition, 用於定義一個類的相關資訊, 只要有物件關聯物件資訊,就會存在一個BeanDefinition
隨後, 此類資訊會被儲存至BeanFactory(bean 工廠)。而在BeanDefinition 與BeanFactory 之間,存在著一個名為BeanDefinitionRegistry (橋樑註冊器)的元件, 透過這個註冊器,能夠將bean 定義註冊到BeanFactory 中

bean 的載入時一個複雜但有序的過程, 確保了應用程式能夠正確獲取和使用所需的物件
1. 首先, spring 會去讀取配置資訊, 可以是xml 檔案, 識別其中定義的bean 元素, 對於註解方式, spring 會掃描指定的包或者類路徑,查詢帶有相關注解的類(Component,Service 等)
2. 然後,對於有依賴關係的bean, spring 會按照依賴的順序進行處理, 會優先載入被依賴的bean, 以確保在建立當前bean 時, 所需依賴都已經準備好
3. 在建立bean 例項時,如果是透過建構函式注入依賴,spring 會呼叫相應的建構函式,並傳入已經準備好的依賴物件,如果是透過屬性設定或者方法注入,spring 會在例項建立後進行相應的注入操作
4. 在例項建立和依賴注入完成後,spring 可能會執行一些初始化回撥方法,例如實現了InitializingBean 介面的afterPropertiesSet 方法, 或者透過配置指定的初始化方法
5. 然後根據bean 的作用域, 如果是單例bean, 會將其儲存在一個共享的快取中,以便後續的請求能夠直接獲取, 如果是原型bean, 則每次請求都會建立新的例項
6. 在整個載入過程中, spring 還會處理一下異常情況, 例如依賴無法滿足、初始化失敗等,並提供相應的錯誤處理機制

1. 前戲, 做容器重新整理前的準備工作, prepareRefresh()
2. 獲取BeanFactory 物件, 完成XMl配置檔案的載入解析, beanDefinition, bean 定義, obtainFreshBeanFactory()
3. BeanFactory 的準備工作, 對各種屬性進行填充, prepareBeanFactory(beanFactory)
4. 交給子類擴充套件的方法, postProcessBeanFactory(beanFactory)
5. 呼叫各種beanFactory處理器, invokeBeanFactoryPostProcessors(beanFactory)
6. 註冊bean處理器, 這裡只是註冊功能(registerBeanPostProcessors(beanFactory))
7. 為上下文初始化message 源, 即不同語言的訊息體,國際化處理 ()initMessageSource
8. 初始化事件監聽多路廣播器 initApplicationEventMulticaster 
9. 留給子類初始化其他的bean onRefresh()
10. 在所有註冊的bean 中查詢listenerBean 註冊到訊息廣播器中
11. 初始化剩下的單例項 finishBeanFactoryInitialization(beanFactory)
12. 完成重新整理過程, 併發出相關通知, finishRefresh
13. 為防止bean 資源佔用, 在異常處理中, 銷燬已經在前面過程中生成的單例bean destroryBeans
14. 重置active 標誌 cancelRefresh(ex)

3.3 bean 的生命週期

1. bean 的生命週期, 整體可以囊括為 例項化、賦值、初始化、使用和銷燬
2. 首先是例項化, spring 會根據配置檔案或者註解等定義資訊去進行建立bean 的例項
3. bean 物件建立之後, 會對其進行屬性賦值, 包括透過建構函式,set方法或者欄位直接注入等方式
4. 然後在初始化前, 會有一些前置處理, 可以修改屬性值或者新增額外功能, 要求bean 實現了BeanPostProcessor 介面的PostProcessBefore 方法
5. 然後是透過init-method 方法或者透過InitializingBean 介面的afterPropertiesSet 方法對bean 進行初始化
6. 初始化之後對bean 的後置處理, 要求實現了BeanPostProcessor 介面的postAfter 方法
7. 之後是bean 的使用, 可以提供相應的服務或者功能
8. 最後就是當應用關閉或者不再被需要時,進入銷燬階段,如果bean 實現了Disposablebean 介面, 其destroy 方法會被呼叫, 如果指定了銷燬方法, 也會在此時執行,以釋放自由、關閉連線

4. 對AOP的理解

AOP 即面向切面程式設計,也可以說是OOP, 物件導向程式設計的補充和完善. AOP是OOP的一種方式
在程式碼執行過程中,動態嵌入其他程式碼,即叫做面向切面程式設計,其本質上是java動態代理在執行時,框架根據我們定義的Pointcut 和 advice, 為目標生成代理物件,
提供了一種非常優雅的方式來解決橫切關注點的問題, AOP能夠將這些橫切關注點從業務邏輯中分離出來,集中在一個地方進行定義和管理

5. spring 的事務

5.1 jdbc 事務的概念

1. 獲取連線物件
2. 獲取statement 物件
3. 關閉事務自動提交
4. 增刪改sql 語句的插入
5. 執行sql 
6. 事務提交/回滾
        String url = "";
        String username = "";
        String password = "";
        Connection conn = null;
        Statement stmt;
        try {
            // 建立資料庫連線
            conn = DriverManager.getConnection(url, username, password);
            // 
            stmt = conn.createStatement();
            // 關閉自動提交
            conn.setAutoCommit(false);
        
            String insertSql = "insert into wrk_info values()";
            // 執行sql
            stmt.execute(insertSql);
            // 提交事務
            conn.commit();
            // 關閉連線
        } catch (Exception e) {
           if (null != conn){
               try {
                   // 異常回滾事務
                   conn.rollback();
               } catch (SQLException ex) {
                   throw new RuntimeException(ex);
               }
           }
            e.printStackTrace();
        } finally {
            if (null != conn){
                try {
                    // 關閉事務連線
                    conn.close();
                } catch (SQLException e) {
                    throw new RuntimeException(e);
                }
            }
        }

5.2 spring 事務

spring 的事務是基於資料庫事務的概念,透過程式設計式事務或者宣告式事務兩種方式來實現
1. 程式設計式事務,需要在程式碼中顯式的控制事務的開始、提交和回滾,透過獲取TransactionManage 物件,並呼叫相應的方法來管理事務。
這種方式靈活,但程式碼侵入性較高,維護起來相對複雜
2. 宣告式事務,透過xml配置或者註解來定義事務的屬性,如傳播行為、隔離級別、超時時間等,spring 會在執行時根據這些配置自動管理事務

透過 TransactionManager 物件,獲取事務的一些相關方法
透過getTransaction 來獲取事務, 獲取事務之後透過doBegin 來開啟事務和連線, 同時會關閉事務的自動提交
透過commit 來提交事務
透過rollback 來回滾事務

宣告式事務, @Transaction 註解, 其原理和上面宣告式事務類似,只不過是透過aop 的形式去建立了transactionDefinition , 
透過代理的形式去建立了對應的TransactionManager 

5.3 Transaction 註解如何注入到容器的

1. 首先需要在啟動類中開啟事務, @EnableTransactionManagement
2. 在@EnableTransactionManagement 註解中, 有一個@Impor 引入了TransactionManagementConfigurationSelector 類
3. 在對應的selectImports 中, 透過proxyTransactionManagementConfiguration 類去獲取全限定類名, 用於 selectImport 注入
4. 

5.4 事務的傳播屬性

在  spring 中, 一共存在7個事務的傳播行為,分別是
1. required, 支援當前事務,沒有事務時, 新建事務
2. supports, 支援當前事務,沒有事務時,以非事務執行
3. mandatory, 支援當前事務,沒有事務時,拋異常
4. required_new, 新建事務,存在事務則掛起
5. not_supports, 以非事務執行,存在事務則掛起
6. never, 以非事務執行,存在事務則拋異常
7. nested, 巢狀事務,存在事務巢狀事務,不存在事務新建事務

5.5 事務的隔離級別

spring 的事務隔離級別是根據資料來源的隔離級別走的,
常見的隔離級別有4種,分別是讀未提交,有 髒讀,幻讀,不可重複度問題。
讀已提交,有幻讀不可重複讀問題
可重複讀,有幻讀問題
序列化,沒有任何問題,只是慢

髒讀: 事務讀取到其他事務未提交資料
不可重複讀: 事務的兩次讀取查詢,因為另一個事務修改,導致資料不一致
幻讀: 事務的多次讀取查詢, 資料量結果集不同

6. spring迴圈依賴問題

迴圈依賴 是指在多個例項或者類之間存在相互依賴的關係,形成一個閉環
在spring 中,迴圈依賴主要有 構造器注入迴圈依賴以及屬性設值迴圈依賴 兩種情況
其中 構造器注入迴圈依賴,無解, spring 只是幫我們解決了屬性賦值的迴圈依賴問題
透過三級快取+提前暴露,解決了 迴圈依賴問題
一級快取:儲存已經經歷完整生命週期的bean 物件
二級快取:儲存早期暴露的bean物件,其生命週期未結束,屬性還未填充完整
三級快取:儲存可以存放bean的工廠

bean 的建立包括有例項化、屬性注入和初始化等, 當出現迴圈依賴時,spring 會先將部分建立的A物件放入三級快取,然後去建立A物件依賴的B物件,如果在建立B物件的時候,發現其又依賴於A物件,就從三級快取中獲取部分建立的A物件並放入二級快取,完成B物件的建立後放入一級快取,然後繼續建立A物件,此時A可以從一級快取獲取完整的B物件,完成A物件的建立並放入一級快取
要求迴圈依賴的bean 必須是單例,並且不為構造器注入

7. spring mvc 處理流程

1. 客戶端發起請求, 透過瀏覽器或者其他客戶端向伺服器傳送http請求
2. DispatcherServlet 接收請求
3. DispatcherServlet 根據URL 透過handlerMapping 找到處理該請求的controller 
4. controller 接收請求引數,並進行相應業務邏輯處理
5. 控制器在處理過程中,可能會運算元據模型,準備要返回給檢視的資料
6. 控制器處理完成之後,返回一個邏輯檢視名,DispactherServlet 透過 檢視解析器解析檢視,找到對應的實際檢視
7. 獲取模型中的資料, 對檢視進行渲染
8. DispatcherServlet 將渲染後的檢視響應給客戶端

8. SpringBoot 自動裝配原理

1. @SpringBootApplication 註解加在啟動類上
2. 在這個註解裡面,主要需要看下@EnableAutoConfiguration 註解, 這個註解, 主要用於載入各種boot-starter 下載配置項, 
3. 在@EnableAutoConfiguration 中存在一個@Import 註解, 會引入一個 AutoConfigurationImportSelector 的類
4. 在這個類中,會透過 springFactoriesLoader 去load 對應配置類資訊, 而這個路徑所對應的地址是 META 下的spring.factories , 
5. 其會透過classLoaer 去獲取對應的resources, 
6. 同時其還可以load META-INF下, spring 下的 org.springframework.boot.autoconfigure.AutoCOnfiguration.imports 檔案中的全限定類名


8.1 @Import 註解的作用

1. import 可以匯入配置類, 透過在主配置類上使用@Import 註解, 可以匯入其他配置類, 使其可以成為該主配置類的一部分,方便組織配置類,使程式碼更加清晰
2. 匯入普通類,除了匯入配置類,@Import 還可以匯入普通類,可以在spring 容器中建立這些類的例項並進行管理
3. 匯入importSelecor 實現類, 透過這種方式根據條件動態選擇要匯入的類
4. 匯入importBeanDefinitionRegistrar 實現類, 透過這種方式在執行時動態註冊bean 到Spring 容器中

相關文章