一直以來都把精力花在中間件的研究和系統設計上,忽略了離我最近的spring,最近開始學習spring的源碼了,為了學習到成體系的spring知識和提高學習效率,想要找了一本書看,最終選的是郝佳的《Spring源碼深度解析(第2版)》,雖然這本書在豆瓣上褒貶不一,但是spring源碼相關的確實也沒有很高評分的書,有的也是很老的spring版本,看了這本書的目錄后還是決定試一試。不過我只會以這本書的內容框架作為我學習的內容框架。并不會完全只參考這本書,對于一些有疑惑的知識我也會搜集多方資料作對比,文章內容也不會完全以這本書的內容為準,最后我會從我自己的角度評價一下這本書。
然后我也打算在學習spring源碼的過程中做一些筆記,把核心內容和自己的理解記錄下來,首先是因為和一個朋友有定期發布文章的約定,而且也能夠通過做一些筆記來加強自己的記憶,在后面淡忘的時候也能通過自己的筆記快速回憶起來這塊內容,最后還能通過輸出內容來為自己的學習增加動力,讓自己看到階段性的成果。
首先記錄一下spring的基本架構,基礎概念和相關環境搭建
一 基本架構
在學習和部署spring源碼之前我們有必要先了解一下spring的基礎,包括spring的架構還有相關的核心概念,Spring框架是一個分層架構,每一層包含一系列的功能要素,分為約20個模塊,下面就是spring的架構圖
1.1. Core Container層
Core Container層提供IoC容器功能,包含了Spring的通用工具類,公共抽象接口和容器內對Bean的定義、配置、創建、生命周期管理、依賴注入等能力的支持。是Spring 的根基,所有上層模塊(AOP、Data Access、Web 等)均基于 Core Container 實現。
1.1.1?Core模塊
Core模塊提供了Spring 的核心工具類、資源訪問抽象和IoC 容器的最低層接口定義,比如模塊內的BeanFactory定義了Bean 的獲取,是否存在,是否是單例等方法,Resource作為統一資源訪問抽象接口,屏蔽不同資源位置(classpath、file、URL)的訪問差異,定義了判斷資源是否存在,獲取輸入流的方法。其他模塊都會依賴這個模塊。
1.1.2 Beans模塊
Beans模塊提供 Bean定義、配置解析、注冊、依賴注入、屬性裝配等Bean生命周期管理的實現。比如模塊內的BeanDefinition用于記錄Bean的名稱,類信息,屬性值,構造函數參數,生命周期回調方法等,BeanWrapper則用于封裝對Bean對象進行屬性封裝與操作。主要就是設置和獲取Bean對象的屬性值。
1.1.3 Context 模塊
Context模塊提供了管理容器上下文模塊的能力,比如獲取容器的某個Bean(依賴于Core模塊的BeanFactory接口),加載國際化資源,發布事件,訪問各種資源等等,比如Context模塊定義和實現了國際化消息解析接口MessageSource,MessageSource接口定義了根據locale獲取本地化字符串的方法,Context模塊還提供了用于Spring事件發布監聽機制的事件類(ApplicationEvent),事件監聽類(ApplicationListener)等接口和實現類。這些能力可以通過模塊提供的聚合類ApplicationContext類來完成。
1.1.4 Expression (SpEL) 模塊
SpEL(Spring Expression Language)是 Spring 提供的一個功能強大的表達式語言,用于在運行時查詢和操作對象圖。主要功能包括訪問對象屬性、調用對象方法,類的靜態方法,計算表達式的值(算術運算、邏輯運算、關系運算等),在Spring中用于配置文件中動態計算值(如 @Value
注解),Spring Security 的權限表達式等地方,比如@Value("#{T(java.lang.Math).random() * 100.0}")里面的"#{T(java.lang.Math).random() * 100.0}"就是SpEl,表示獲取值時調用Math的random()方法并乘于100.0,
SpEL模塊的功能就是提供SpEL相關的能力,比如SpEL的解析和計算,比如SpEL模塊的ExpressionParser接口就是用于解析表達式字符串,生成 Expression 對象。
1.1.5 Instrument模塊
提供類加載器級別的工具,主要用于類增強,支持類加載時織入(Load-time Weaving, LTW),在類加載到 JVM 時對類進行增強,Spring AOP和AspectJ LTW都需要此模塊來配合。模塊里面比較重要的類就是InstrumentationSavingAgent類了,它在JVM 啟動時運行,保存Instrumentation對象供后續使用。主要用于支持JPA weaving。
這里的Instrumentation是指JDK 提供的Instrumentation API,位于 java.lang.instrument包。JVM 啟動時,若使用了 -javaagent 參數,并且 agent jar 的 MANIFEST.MF 中配置了 Premain-Class,JVM 會調用該類的 premain(String, Instrumentation) 方法,并傳入Instrumentation對象,Instrumentation 提供對JVM的運行時檢測與字節碼修改能力主要功能包括注冊 ClassFileTransformer,實現 load-time weaving(加載時織入),獲取JVM已加載的所有類信息,重定義已加載類的字節碼(在支持的 JVM 下),這個是JDK自帶的功能,這里就不仔細介紹了。有興趣的讀者可以專門去研究一下。
1.1.6 JCL模塊
Jakarta Commons Logging 是 Apache 提供的一個 日志抽象框架,全稱 Commons Logging,常簡稱 JCL。它是 日志抽象層,而不是具體的日志實現。提供統一的日志 API,底層可對接 Log4J、Java Util Logging(JUL)等,自動適配 Log4j、SLF4J、JUL。這個模塊主要提供了LogFactory類,用于獲取Log實例,Log類提供統一的日志接口。
1.2. AOP層
AOP(Aspect Oriented Programming)即面向切面編程,是Spring提供的另一核心功能,用于在不修改業務代碼的情況下,將橫切邏輯(日志、事務、權限校驗、監控等)織入目標代碼中,提高代碼模塊化和可維護性。Aop層就是Spring提供的AOP的能力,
1.2.1 AOP模塊
AOP模塊為Spring提供了基于代理的切面編程能力,實現了切面(Aspect)、通知(Advice)、切入點(Pointcut)、織入(Weaving)等AOP基本概念的抽象與實現。這里主要定義切面編程的基礎接口(Advice、Pointcut、Advisor 等),提供基于 JDK 動態代理(接口代理)或 CGLIB(子類代理)的 AOP 實現,與 IoC 容器集成,實現聲明式事務管理、方法攔截、權限控制等功能
Advice:通知,定義在 JoinPoint 處要執行的動作
Pointcut:切點,定義匹配哪些連接點
Aspect:切面,是 通知(Advice)和切點(Pointcut)的組合,它定義了 橫切關注點 的整體。
1.2.2?Aspects模塊
Aspects模塊是 Spring 對 AspectJ 框架的支持模塊,提供了與 AspectJ 的整合功能,提供對 AspectJ 注解風格切面的支持(@Aspect),支持 AspectJ 的 Load-time Weaving(加載時織入)和 Compile-time Weaving(編譯時織入)并且使Spring容器能夠識別和處理 AspectJ 定義的切面,定義了@Aspect @Before, @After, @Around, @AfterReturning, @AfterThrowing等注解,需要依賴上面的AOP模塊提供的代理來實現其處理邏輯,
1.3. Data Access/Integration層
Data Access/Integration層是Spring的數據訪問和集成層,提供spring對數據庫訪問、ORM框架整合、事務管理、消息傳遞,遠程調用,緩存,任務調度等的支持,提供連接和集成外部系統(數據庫,外部服務等)的能力。
1.3.1 JDBC 模塊
JDBC模塊通過封裝JDBC,包括封裝 Connection/Statement/ResultSet 處理,統一異常處理等,簡化了對數據庫的連接和操作,比如模塊定義和實現了JdbcTemplat接口來提供簡單易用的數據庫調用API。定義了和實現了RowMapper接口, 將 ResultSet 的每一行映射為 Java 對象
1.3.2 ORM模塊
ORM模塊顧名思義就是集成 Hibernate、JPA、MyBatis 等 ORM 框架。比如實現了JPA 事務管理器JpaTransactionManager,配置Hibernate SessionFactory的工廠Bean,LocalSessionFactoryBean類
ORM(Object-Relational Mapping)是一種程序設計技術,用于將面向對象編程語言中的對象(Java 對象)與關系型數據庫(RDBMS)的表 進行映射,使得: 你可以直接通過操作對象(例如 Java Bean),來實現對數據庫表的插入、更新、查詢、刪除(CRUD), 而不需要手動編寫繁瑣的 SQL 語句和 ResultSet 解析。
1.3.3 JMS 模塊
JMS模塊封裝了Java Message Service,提供一套更加簡單易用的消息發送與監聽API。模塊內提供了JmsTemplate類,用于發送與接收消息和管理Connection/Session/Producer/Consumer,也提供了MessageListener類異步消息監聽接口
1.3.4 Messaging模塊
提供消息抽象模型,支持消息通道、處理器,比如定義了Message來表示消息,包含消息頭和消息體,定義了MessageChannel來表示消息傳輸通道。
1.3.5 Transaction (tx) 模塊
tx模塊提供了spring的聲明式/編程式事務管理能力。比如定義了核心事務管理接口PlatformTransactionManager,包括了獲取事務狀態,提交和回滾事務的方法。以及提供了TransactionDefinition用來定義事務隔離級別、傳播行為、超時時間。其他的比如JMS,ORM等模塊需要用到事務的地方都會實現自己的PlatformTransactionManager來實現事務能力。
1.3.6 OXM模塊
OXM就是Object-XML Mapping,OXM模塊主要就是支持將Java對象與XML相互轉換。主要有兩個核心接口,將對象序列化為XML的Marshaller接口和將XML反序列化為對象的Unmarshaller
1.4 Web層
Web層是 Spring 提供的 面向 Web 應用程序的功能層,主要用于構建基于 Servlet 的 Web 應用、RESTful API、以及響應式 Web 應用,提供了處理 HTTP 請求、請求路由分發、參數綁定、數據轉換、視圖解析、異常處理、WebSocket 通信等能力。也是Spring面向用戶請求的最外層,作為用戶與應用程序交互的入口,負責接收并處理來自瀏覽器或客戶端的請求,將請求數據傳遞給業務邏輯層,并將業務邏輯層返回的結果封裝成 HTTP 響應或 WebSocket 消息返回給用戶。
1.4.1 Web模塊
Web模塊提供 Spring 基礎的 Web 功能支持,包括封裝 Servlet API、文件上傳解析、客戶端 REST 調用等功能。比如模塊提供了 MultipartResolver 接口用于多部分文件上傳解析,提供了 RestTemplate 類,封裝了基于HttpURLConnection或Apache HttpClient 的 REST 調用邏輯,提供了便捷的 GET、POST、PUT、DELETE 方法。Web層的其他模塊也都會依賴Web模塊來完成網絡傳輸。
1.4.2 Web MVC模塊
Web MVC模塊就是Spring的Web MVC框架實現模塊,提供了基于Servlet的MVC架構,核心是 DispatcherServlet類,作為前端控制器,接收所有請求并分發給相應的 Handler處理。模塊的主要組件有負責根據請求URL匹配處理器的HandlerMapping,調用處理器方法的HandlerAdapter,負責解析視圖名稱為實際View對象的ViewResolver,封裝模型數據與視圖名稱的對象ModelAndView等等,同時支持注解控制器(@Controller, @RequestMapping)以及數據綁定、參數解析、異常處理、攔截器等能力。
1.4.3 WebFlux模塊
WebFlux模塊提供了 Spring 5 引入的響應式 Web 框架,基于 Reactor 提供的 Flux/Mono 實現非阻塞式編程模型,適用于高并發 IO 密集型場景。 模塊提供了函數式編程風格的路由與處理 WebFlux.fn,注解風格支持@RestController + RouterFunction,將各種響應式庫類型適配為 Flux/Mono的ReactiveAdapterRegistry, WebFlux 可以運行在 Netty、Undertow 等非 Servlet 容器,也可運行在支持 Servlet 3.1+ 的容器上。
1.4.4 WebSocket 模塊
WebSocket模塊為Spring提供了基于WebSocket協議的雙向通信支持,支持瀏覽器與服務器建立持久連接,實現實時消息推送。比如模塊定義和實現了WebSocketHandler接口用于處理WebSocket消息,提供了SockJsClient和SockJsService對SockJS協議進行支持,兼容不支持原WebSocket的瀏覽器,也提供了注解配置支持@EnableWebSocket和@ServerEndpoint,底層可結合 Spring Messaging 模塊進行消息編程,支持 STOMP 協議集成
1.5 Test層
Test層主要提供對 JUnit/TestNG 的集成,用于項目進行一些Mock測試和Web測試。
1.5.1 Test 模塊
支持Spring容器的單元測試和集成測試。比如提供了在JUnit中加載Spring ApplicationContext的SpringJUnit4ClassRunner / SpringRunner,用于測試Spring MVC 控制器的MockMvc,以及@SpringBootTest ,@WebMvcTest等測試注解
二? 環境搭建和依賴導入
如果你對java和spring的使用還不熟悉,是不建議自己看spring的源碼的,這樣不僅會浪費你很多時間,而且很多地方也無法真正看懂,所以這里會假設你電腦已經裝備了java環境并且已經有了一定的開發經驗。
2.1 引入項目
在github上拉取Spring核心代碼
我們直接在github上拉取spring的源碼,當然,如果你有定制化spring或者參與spring建設的野心你也可以先fork一下spring的源碼再拉取,如果不想科學上網的話也可以從gitee等平臺上拉取spring的鏡像。我們這里直接在idea上拉取spring5.2.x的代碼
github:https://github.com/spring-projects/spring-framework/tree/5.2.x
git:https://github.com/spring-projects/spring-framework.git
2.2 依賴導入
設置maven倉庫鏡像
引入項目后我們需要修改一下build.gradle文件,設置一下maven倉庫鏡像,不然運行build太慢了
repositories {mavenCentral()maven { url "https://repo.spring.io/libs-spring-framework-build" } }
改為
repositories {maven{ url 'https://maven.aliyun.com/nexus/content/groups/public/'}maven{ url 'https://maven.aliyun.com/nexus/content/repositories/jcenter'}mavenCentral()maven { url "https://repo.spring.io/libs-spring-framework-build" } }
編譯compileTestJava模塊
./gradlew :spring-oxm:compileTestJava
最后看到
BUILD FAILED in 1m 30s
編譯測試完成,說明代碼沒問題
然后在idea上導入spring依賴
也可以直接使用命令
?./gradlew build
提示
提示要我使用java12來作為gradle的jvm,而我現在是Java21,然后我在idea上調整一下gradle的jvm
重新執行,經過兩年半的時間依賴導入完成了,后面就可以開始學習代碼了
BUILD SUCCESSFUL in 29m 36s
BUILD SUCCESSFUL in 409ms
2.3?番外知識 AspectJ
AspectJ 是一個面向切面編程的擴展框架,為 Java 提供了完整的 AOP 語法和編譯器支持,Spring使用了AspectJ技術來實現Aop,使用aj文件來編寫Aop邏輯,普通的javac并不能編譯這些aj文件,需要使用AspectJ編譯器ajc(增強版javac)來編譯項目,才能把aj文件編譯為class文件,當然spring源碼的gradle配置上已經引入了AspectJ,并且在構建項目時候能夠使用它來編譯aj文件,正常情況下我們不需要自己安裝aspectJ,但是我這里也額外記錄一下自己安裝AspectJ。
下載和安裝aspectJ編譯器
我們直接進入aspectJ的github頁面下載,下載最新版本的jar包就好了
github頁面:https://github.com/eclipse-aspectj/aspectj/releases/
下載后運行這個jar包
java -jar aspectj-1.9.24.jar??
彈出彈窗
跟隨彈窗引導安裝,最終點擊finish就完成了安裝,中間我們可以選擇自己的安裝目錄,安裝完成后可以去自己安裝目錄看看是否已經有了,如圖所示