源碼下麵無秘密,這是程式員的口頭禪。對於強大而且設計優秀的Spring框架也是這樣的,在基礎代碼層層堆疊之下,Spring成為了一個非常流行的框架。 ...
源碼下麵無秘密,這是程式員的口頭禪。對於強大而且設計優秀的Spring框架也是這樣的,在基礎代碼層層堆疊之下,Spring成為了一個非常流行的框架。
Spring6框架的開發者們通過層層設計和封裝打造了一個功能如此之多而相容性非常好的框架。這也是解構這個框架難點,而通過理解整個框架功能的實現也差不多瞭解了整個Spring的生態,甚至是整個java開發生態的大部分知識。
Spring6框架包含哪些內容
通過SpringFramework6的源碼可以看到,Spring包含如下幾個模塊:
spring-aop
:提供了面向切麵編程(AOP)的支持,允許在代碼中分離橫切關註點。spring-aspects
:包含了用於實現 AOP 的AspectJ 集成和 weaving 功能。spring-beans
:是 Spring 框架的核心模塊之一,提供了對 JavaBean 的配置和管理。spring-context
:提供了應用程式上下文的管理和配置,包括依賴註入和上下文的生命周期。spring-context-indexer
:用於支持 Spring Context 的索引和搜索功能。spring-context-support
:提供了一些額外的上下文支持,如緩存、事件發佈和監聽器等。spring-core
:是 Spring 框架的基礎模塊,包含了一些核心的工具和類。spring-core-test
:是 Spring 核心模塊的測試支持。spring-expression
:提供了一種強大的表達式語言,用於在配置文件和註解中解析和操作對象。spring-instrument
:用於在應用程式運行期間動態檢測和修改類的行為。spring-jcl
:提供了 JCL(Jakarta Commons Logging)的集成和日誌管理。spring-jdbc
:提供了對 JDBC 資料庫操作的簡化和封裝。spring-jms
:用於與 JMS(Java Message Service)消息隊列的集成。spring-messaging
:是一個通用的消息傳遞抽象和實現。spring-orm
:提供了對 ORM(Object Relational Mapping)框架的集成支持。spring-oxm
:是 Spring Object/Relational Mapping(ORM)模塊的一部分。spring-r2dbc
:用於與 Reactive Relational Database Connectivity(反應式關係型資料庫連接)的支持。spring-test
:提供了用於測試 Spring 應用程式的工具和類。spring-tx
:提供了對事務管理的支持。spring-web
:是 Spring 框架的 Web 模塊,提供了 Web 應用程式的開發支持。spring-webflux
:用於構建反應式 Web 應用程式。spring-webmvc
:是傳統的 Spring MVC 框架,用於構建 Web 應用程式。spring-websocket
:用於實現 WebSocket 通信。
這些模塊基本就是Spring6框架的全部核心了。
Spring6框架如何深入瞭解
如何深入瞭解Spring框架呢?
一個很常用的辦法就是通過使用到的api結合源碼來分析和理解。api給程式員一個直觀的體驗,這個api是什麼,就有什麼功能。
當想要理解原理的時候,就可以結合源碼來來瞭解原理和實現方式。源碼下麵無秘密。
另外一方面就是通過實現介面或者仿寫介面來更加深入的理解源碼當中的原理。為什麼要這樣寫而不是其它方式呢?性能還是復用?通過實現介面肯定能學到更多東西。
這裡就有一個大概的學習Spring6框架的模板了。
- 編寫demo使用api
- 閱讀api的源碼和實現
- 編寫api的實現
- 編寫單元測試
以Sping6框架中核心類org.springframework.beans.factory.BeanFactory
為例說明整個研究和學習過程。
介面org.springframework.beans.factory.BeanFactory#getBean
,它的主要功能如下:
-
返回指定 bean 的一個實例,該實例可以是共用的或獨立的。
-
這種方法允許 Spring BeanFactory 用作 Singleton 或 Prototype 設計模式的替代品。在 Singleton bean 的情況下,調用者可能會保留對返回對象的引用。
-
將別名轉換回相應的規範 bean 名稱。
-
如果在該工廠實例中找不到該 bean,則將向父工廠詢問。
-
編寫使用demo
package io.yulin.learn.spring.s100;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.stereotype.Component;
/**
* BeanFactory獲取Bean使用demo
* @author r0ad
* @since 1.0
*/
@SpringBootApplication
@Slf4j
public class BeanFactoryGetBean {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(BeanFactoryGetBean.class, args);
log.info("當前上下文是BeanFactory {}",context instanceof BeanFactory);
ComponentDemo1 componentDemo1 = (ComponentDemo1) context.getBean("ComponentDemo1");
// 測試獲取到的bean的介面
componentDemo1.test();
// 關閉應用
context.close();
}
}
@Component("ComponentDemo1")
@Slf4j
class ComponentDemo1 {
public void test() {
log.info("ComponentDemo1 test");
}
}
輸出的結果如下。可以看到ConfigurableApplicationContext
實現了BeanFactory
的getBean
介面。通過context.getBean("ComponentDemo1")
獲取到的bean就是ComponentDemo1
。而且可以直接調用test
方法。
當前上下文是BeanFactory true
ComponentDemo1 test
我們可以通過一個ConcurrentHashMap來維護bean的實例。通過這個Map實現getBean
方法。
package io.yulin.learn.spring.s100;
import org.springframework.beans.factory.BeanCreationException;
import java.util.concurrent.ConcurrentHashMap;
/**
* 實現 BeanFactory 介面的getBean方法,由於BeanFactory有很多介面,此處演示就沒有直接implements BeanFactory
* @author nine
* @since 1.0
*/
public class BeanFactoryDemoImpl {
private ConcurrentHashMap<String, Object> beans = new ConcurrentHashMap<>();
public Object getBean(String name) throws BeanCreationException {
if (beans.containsKey(name)) {
return beans.get(name);
} else {
throw new BeanCreationException("Bean not found: " + name);
}
}
// 添加方法用於向 ConcurrentHashMap 中添加 bean
public void registerBean(String name, Object bean) {
beans.put(name, bean);
}
// 添加方法用於從 ConcurrentHashMap 中移除 bean
public void removeBean(String name) {
beans.remove(name);
}
}
編寫了一個單元測試並且測試通過。
package io.yulin.learn.spring.s100;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
/**
* 自定義getBean實現的單元測試
* @author nine
*/
public class TestDemoImplGetBean {
@Test
public void testDemoImplGetBean() {
BeanFactoryDemoImpl beanFactoryDemo = new BeanFactoryDemoImpl();
beanFactoryDemo.registerBean("test", new ComponentDemo1());
Object test = beanFactoryDemo.getBean("test");
boolean instanceCheck = test instanceof ComponentDemo1;
assertThat(instanceCheck).isTrue();
((ComponentDemo1) test).test();
}
}
實際實現介面org.springframework.beans.factory.BeanFactory#getBean
要複雜的多。需要實現上文提到的全部功能。以下是一個Spring6框架中的實現。
/**
* 從IoC容器中獲取指定名稱的bean實例。
*
* @param name 要獲取的bean的名稱,可能包含工廠Bean引用首碼
* @return 根據名稱創建或獲取的bean實例
* @throws BeansException 若在獲取、創建或初始化bean過程中發生異常時拋出
*/
public Object getBean(String name) throws BeansException {
// 首先處理並轉換傳入的bean名稱(例如移除FactoryBean首碼等)
String beanName = BeanFactoryUtils.transformedBeanName(name);
// 從容器內部存儲的bean定義集合中查找指定名稱的bean實例
Object bean = this.beans.get(beanName);
// 如果未找到該bean,則拋出 NoSuchBeanDefinitionException 異常
if (bean == null) {
throw new NoSuchBeanDefinitionException(
beanName,
"Defined beans are [" + StringUtils.collectionToCommaDelimitedString(this.beans.keySet()) + "]");
}
// 檢查是否是工廠Bean引用,並確保它實際上是FactoryBean類型
// 若不是工廠Bean卻被嘗試作為工廠Bean引用,拋出異常
if (BeanFactoryUtils.isFactoryDereference(name) && !(bean instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(beanName, bean.getClass());
}
// 如果當前bean是一個FactoryBean,並且調用者沒有顯式要求獲得FactoryBean本身,
// 則通過調用FactoryBean.getObject()方法來獲取由其生成的bean實例
if (bean instanceof FactoryBean<?> factoryBean && !BeanFactoryUtils.isFactoryDereference(name)) {
try {
// 獲取FactoryBean所生產的對象實例
Object exposedObject = factoryBean.getObject();
// 如果FactoryBean返回null,則拋出異常
if (exposedObject == null) {
throw new BeanCreationException(beanName, "FactoryBean exposed null object");
}
// 返回由FactoryBean生成的對象實例
return exposedObject;
}
catch (Exception ex) {
// 若在調用FactoryBean.getObject()過程中出現任何異常,包裝成BeanCreationException拋出
throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
}
}
else {
// 如果bean不是FactoryBean,或者請求的是FactoryBean自身,直接返回bean實例
return bean;
}
}
通過上述整個過程的實戰和源碼分析,可以對Spring6的核心功能有一個更加清晰的瞭解和感悟。
Spring6框架需要瞭解哪些內容
通過Spring6框架的官方文檔可以找到大致的框架。
Spring的文檔一直以來都是非常清晰的。尤其是在無數次迭代之後更能體現Spring的設計之美。
其中Spring6框架大致分為6個大類,每個大類對應很多小類和技術細節。
這6個大類分別是:
CORE 核心技術:
Spring 框架的核心技術包括 IoC 容器、依賴註入、AOP、事件機制等。IoC 容器提供了對象的生命周期管理和依賴關係的維護,依賴註入通過配置或註解的方式實現對象之間的解耦,AOP 支持面向切麵編程,而事件機制則允許應用程式中的組件之間進行事件通知和處理。
TESTING 測試:
Spring 框架提供了豐富的測試支持,包括單元測試、集成測試、模擬對象、測試數據準備等功能。通過 Spring 的測試框架,開發人員可以方便地編寫和運行各種類型的測試,並且能夠與 Spring 應用程式的其他部分無縫集成。
Data Access 數據訪問:
Spring 的數據訪問層提供了對 JDBC、ORM 框架(如 Hibernate、MyBatis)、NoSQL 資料庫(如 MongoDB、Redis)等的支持,同時也提供了事務管理、數據源管理、數據訪問模板等功能,簡化了數據訪問層的開發。
Web Servet:
在 Web Servlet 領域,Spring 框架提供了對 Servlet、JSP、WebSocket、Web MVC 等的支持,包括處理請求、視圖解析、控制器、攔截器等功能,同時也提供了 RESTful Web 服務的開發支持。
Web Reactive:
Spring Web Reactive 則是針對響應式編程模型提供支持,包括非阻塞 I/O、非同步處理、反應式流等特性,同時提供了 WebFlux、WebClient、WebSocket、RSocket 等組件,用於構建響應式的 Web 應用程式。
Integration 集成:
Spring 提供了對 REST Clients、JMS、JCA、JMX、Email、Tasks、Scheduling、Caching、Observability、JVM Checkpoint Restore 等集成功能的支持,使得應用程式可以方便地與外部系統集成,並且具備了更好的可觀察性和可擴展性。
CORE 核心技術:
- IoC Container(控制反轉容器):Spring 的核心功能之一,通過 IoC 容器管理和組織應用程式中的對象及其依賴關係。它負責實例化、配置和管理這些對象,以及處理它們之間的依賴註入。
- Events(事件):Spring 的事件機制允許應用程式中的組件發送和接收事件。這種松耦合的通信方式可以用於實現模塊之間的交互和觸發非同步操作。
- Resources(資源載入):Spring 提供了統一的資源載入機制,使得應用程式可以輕鬆地訪問不同類型的資源,如文件、類路徑資源、URL 等。
- i18n(國際化):Spring 提供了國際化支持,使得應用程式能夠根據用戶的語言環境展示不同的文本消息和格式化數據。
- Validation(驗證):Spring 的驗證框架提供了一種方便的方式來驗證表單數據和其他輸入數據的有效性。它支持各種驗證規則和自定義驗證器。
- Data Binding(數據綁定):Spring 提供了強大的數據綁定機制,可以將請求參數、表單數據等與 Java 對象進行綁定,簡化了數據傳輸和處理的過程。
- Type Conversion(類型轉換):Spring 的類型轉換機制可以自動將一種類型的值轉換為另一種類型,使得應用程式在處理不同數據類型時更加靈活和方便。
- SpEL(Spring 表達式語言):SpEL 是一種強大的表達式語言,允許在運行時對對象圖進行查詢和操作。它可以在配置文件中使用,也可以在運行時通過編程方式使用。
- AOP(面向切麵編程):Spring 的 AOP 支持通過代理機制實現橫切關註點(如日誌、事務管理等)的模塊化開發。它通過切麵、連接點和通知來實現對目標對象的增強。
- AOT(Ahead of Time Compilation,預編譯):AOT 是 Spring 框架的一個最新功能,通過提前將 Spring 應用程式的位元組碼編譯成本地機器代碼,以提高應用程式的性能和啟動速度。
以上是關於 Spring 框架中 CORE 核心技術的功能說明,它們共同構成了 Spring 的基礎,併為開發者提供了很多有用的特性和工具。
TESTING 測試:
- Mock Objects:Spring 允許創建和使用模擬對象(Mock Objects),這些對象可以替代真實的對象進行單元測試,以便更容易地隔離被測試的組件。
- TestContext Framework:Spring 的 TestContext 框架提供了一種統一的方式來載入和管理應用程式上下文,使得在測試中可以方便地使用 Spring 容器和其他功能。
- Spring MVC Test:Spring MVC Test 提供了對 Spring MVC 應用程式進行集成測試的支持,可以模擬 HTTP 請求和響應,驗證控制器的行為和視圖的渲染結果。
- WebTestClient:WebTestClient 是 Spring WebFlux 模塊提供的用於測試 WebFlux 應用程式的客戶端工具,可以進行非同步、非阻塞的 Web 應用程式測試。
這些功能使得在 Spring 框架中進行單元測試、集成測試和端到端測試變得更加簡單和高效。
Data Access 數據訪問:
- Transactions(事務):Spring 框架提供了強大的事務管理功能,支持聲明式事務和編程式事務,以確保資料庫操作的一致性和可靠性。
- DAO Support(DAO 支持):Spring 提供了對數據訪問對象(Data Access Object)的支持,通過封裝資料庫訪問邏輯到 DAO 中,簡化了數據訪問層的開發和維護。
- JDBC:Spring 對 JDBC(Java Database Connectivity)提供了高度集成的支持,通過 JDBC Template 等類,簡化了資料庫訪問的代碼編寫,並處理了資源管理和異常處理等細節。
- R2DBC:Spring 通過支持 R2DBC(Reactive Relational Database Connectivity),使得在響應式應用程式中進行關係型資料庫的非同步操作更加便捷。
- O/R Mapping(對象關係映射):Spring 提供了強大的對象關係映射支持,通過框架內置的 ORM(Object-Relational Mapping)工具,將資料庫表的記錄映射為 Java 對象,方便進行對象的持久化與操作。
- XML Marshalling(XML 序列化):Spring 提供了對 XML 數據的序列化和反序列化支持,可以方便地將 Java 對象轉換為 XML 格式或將 XML 轉換為 Java 對象,用於處理 XML 數據的讀寫操作。
這些數據訪問功能使得在 Spring 框架中進行數據持久化和操作變得更加簡單、高效和可靠,提升了開發人員的生產力。
Web Servet:
- Spring MVC:Spring MVC 是 Spring 框架中的 Web 模塊,提供了基於模型-視圖-控制器(MVC)設計模式的 Web 應用程式開發支持,用於構建靈活、可擴展的 Web 應用程式。
- WebSocket:Spring 框架支持 WebSocket 技術,可以實現全雙工的通信方式,適用於需要實時性和互動性的 Web 應用程式開發。
- SockJS:SockJS 是一個 JavaScript 庫,Spring 框架通過對 SockJS 的支持,可以實現在不同瀏覽器上對 WebSocket 的相容性,確保更廣泛的客戶端支持。
- STOMP Messaging:STOMP(Simple Text Oriented Messaging Protocol)是一種簡單文本導向的消息協議,在 Spring 框架中提供了對 STOMP 協議的支持,用於實現基於消息的應用程式通信。
這些功能為開發者提供了豐富的選擇,使得在 Spring 框架中開發 Web 應用程式更加便捷、高效,並支持現代化的 Web 開發需求。
Web Reactive:
- Spring WebFlux:Spring WebFlux 是 Spring 框架中的響應式編程模塊,基於 Reactor 庫提供了一種非阻塞的、非同步的編程模型,用於構建高性能、可擴展的響應式 Web 應用程式。
- WebClient:Spring WebClient 是一個非阻塞的、非同步的 HTTP 客戶端,用於在 WebFlux 應用程式中進行遠程服務調用,支持響應式流處理和各種協議。
- WebSocket:Spring 框架通過對 WebSocket 技術的支持,可以實現全雙工的通信方式,用於構建實時的、互動性強的 Web 應用程式。
- RSocket:RSocket 是一種可擴展的、非同步的、多種傳輸協議的消息通信協議,Spring 框架提供了對 RSocket 的支持,用於構建分散式系統中的可靠通信。
這些功能使得在 Spring 框架中開發響應式的 Web 應用程式更加便捷、高效,並能夠處理大量併發請求和實時數據交互。它們適用於需要高性能、可伸縮性和實時性的現代 Web 應用程式開發。
Integration 集成:
- REST Clients:Spring 框架提供了對 RESTful 服務的客戶端支持,可以方便地進行 REST API 的調用和交互,實現與其他服務的集成。
- JMS:Spring 對 Java Message Service(JMS)提供了集成支持,用於在分散式系統中進行非同步消息傳遞,實現應用程式之間的解耦和通信。
- JCA:Spring 框架支持 Java Connector Architecture(JCA),用於與企業信息系統(如 ERP、CRM 等)進行連接和集成,實現企業級應用程式的互操作性。
- JMX:Spring 提供了對 Java Management Extensions(JMX)的支持,用於監控和管理應用程式的運行時狀態,實現應用程式的監控和遠程管理。
- Email:Spring 框架提供了發送和接收電子郵件的功能支持,簡化了電子郵件服務的集成和操作,用於實現郵件通知和交互功能。
- Tasks:Spring 支持非同步任務執行,通過 TaskExecutor 介面和相關類,可以實現非同步任務的調度和執行,提升應用程式的性能和響應速度。
- Scheduling:Spring 提供了任務調度的功能支持,可以通過註解或配置的方式實現定時任務的執行,用於處理周期性任務和定時作業。
- Caching:Spring 框架提供了對緩存的抽象和支持,可以通過緩存註解實現方法級別的緩存,提升應用程式的性能和響應速度。
- Observability:Spring 支持應用程式的可觀察性,包括日誌記錄、指標監控、跟蹤和分析等功能,幫助開發者瞭解應用程式的運行狀態並快速定位問題。
- JVM Checkpoint Restore:Spring 支持 JVM 的檢查點恢復,可以在應用程式異常時保存當前狀態,併在恢復時恢復到之前的狀態,減少數據丟失和影響範圍。
這些功能使得在 Spring 框架中集成其他系統或者擴展變的十分容易。
總結
通過源碼,我們可以看到Spring6框架的核心和組成。
Spring框架的核心技術包括IoC容器、依賴註入、AOP等,為應用程式提供對象生命周期管理、解耦和麵向切麵編程等功能;同時,它擁有豐富的測試支持,簡化了單元測試、集成測試的編寫與執行;在數據訪問層面,Spring全面支持多種資料庫技術,並提供了事務管理、模板類等工具;Web層方面,Spring不僅涵蓋了Servlet/JSP/Web MVC的傳統Web開發,還支持響應式編程模型如WebFlux;此外,Spring還具備強大的集成能力,方便與外部系統交互並實現可觀察性和擴展性。
在“Spring6全攻略”中,後續將通過如下的流程來完成整個Spring6的攻略。
- 編寫demo使用api
- 閱讀api的源碼和實現
- 編寫api的實現
- 編寫單元測試
參考資料
視頻
- 黑馬程式員Spring視頻教程,深度講解spring5底層原理https://www.bilibili.com/video/BV1P44y1N7QG
文檔
- Spring 6 javadoc https://docs.spring.io/spring-framework/docs/6.1.x/javadoc-api/
- Spring 6 參考文檔 https://docs.spring.io/spring-framework/docs/6.1.x/reference/html/
- Spring 6 源碼 https://github.com/spring-projects/spring-framework
關於作者
來自一線全棧程式員nine的八年探索與實踐,持續迭代中。歡迎關註公眾號“雨林尋北”或添加個人衛星codetrend(備註技術)。