Spring 框架介紹和使用
本文主要是對 Spring 的一個基本使用,建議閱讀時間 5min。
歷史的選擇
Spring 作為一個基礎的框架,是在 Java EE 開發歷史中,是成千上萬公司選擇。單獨使用 Spring 的非常少了,很多都是用 Spring-Boot/Spring-Cloud 來開發,但是 Spring 基礎依然是我們使用的基石。我們將一起來聊一聊 Spring 的基本使用。首先我們一起來了解一下 Spring 框架整體架構圖如下:
- 數據訪問/集成,包括 JDBC 、ORM、OXM、JMS 和 Transaction 模塊;
- WEB 模塊,包括 WebSocket、Servlet、Web、Porlet 模塊;
- 核心容器,包括 Bean 模塊、Core 模塊、Context 模塊 和 SpEL 模塊;
- 其他部分,包括:AOP、Test 等模塊
Spring 同類框架
- Micronaut
- Quarkus
Spring 核心功能
核心功能:控制反轉(IOC) 、AOP 非核心功能:事件驅動、國際化、資源管理,數據綁定、類型轉換 、SpEL、單元測試等。
PS:核心功能,在本文會有使用實踐。
Spring Bean 容器
控制反轉(IOC)是 Spring 框架的核心功能之一,其本質的就是將用戶創建 Bean 的過程賦予給 IOC 容器去完成,實現 Bean 創建權利的反轉為容器來創建 Bean 和依賴 Bean 。
Bean 創建
Spring 容器創建 Bean 只需要三個步驟:
- 定義 Bean
- 創建 Bean 容器/Bean 工廠
- 獲取 Bean 對象
舉一個例子:
運行上面的代碼我們可以得到一下結果:
上面的代碼執行什么呢?其實我們可以將 ApplicationContext理解為 Spring 容器對象,然后我們在 AppConfig 配置類中去定義 Spring 容器去幫助我們加載那些 Bean ,最后我們通過 getBean 方法獲取我們注冊的 Bean 對象。如下圖:
在這個過程中使用到那些關鍵的接口/類呢?
- BeanFactory? 是 Bean 的抽象工廠,也就是我們ApplicationContext 的一個父接口。
- BeanDefinition? 是 Bean 的定義信息, 比如 beanName, className, isAbstract? 等 Bean 定義信息。
注入依賴 (DI)
Spring IOC 容器主要是解決了 Bean 的創建和依賴管理的問題。我們常見的有兩種依賴注入方式:
- 屬性注入
- 構造方法注入
屬性注入
通過成員屬性的方式實現 Bean 的自動注入
- 通過@Component可以將 Student 、Address 類標記為一個 bean 對象。
- 通過@Autowired可以將依賴 Bean 自動注入進來。
構造方法注入
通過構造方法實現 Bean 的自動注入。
Spring 的 IOC 解決了什么問題?
- 容器化,Spring包含并管理應用中對象的生命周期和配置(配置成單例還是原型,以及什么時候使用什么時候銷毀)。
- 方便解耦,簡化開發,Spring就是一個大工廠,可以將所有對象創建和依賴關系維護交給Spring管理,實現松耦合。符合高內聚低耦合的思想,這個特性也叫IOC(控制反轉)。
- AOP編程的支持,Spring提供面向切面的編程,可以方便的實現對程序進行權限攔截、運行監控等功能,是通過動態代理和CGlib實現的,底層原理是反射。
- 聲明式事務的支持,通過AOP來實現。不需通過編程的方式而進行管理事務,這樣就不需要在業務邏輯代碼中摻雜事務管理的代碼,只需在配置文件中做相關的事務規則聲明,便可將事務規則應用到業務邏輯中。
- 方便程序的測試,Spring對Junit4的支持,可以通過注解方便的測試Spring程序。
- 方便集成各種優秀框架,Spring不排斥各種優秀的開源框架,其內部提供了對各種優秀框架的直接支持(如Struts2、Hibernate、MyBatis等)。
- 異常處理,Spring提供方便的API把具體技術相關的異常轉化為一致的unchecked異常(比如由JDBC、Hibernate或者JDO拋出的異常)。SpringMVC也有一個異常集中處理的思想,將異常拋給SpringMVC框架,由框架來處理異常。
- 降低JavaEE API的使用難度,Spring對JavaEE開發中非常難用的一些API(JDBC、JavaMail、遠程調用等),都提供了封裝,使這些API應用難度大大降低。
Spring AOP 面向切面
AOP(Aspect Oriented Programming)是面向切面的意思。
理解 AOP
Java 是一個面向對象(OOP)的編程語言,但是它有一個弊端就是需要為多個不具有繼承關系的對象引入一個公共行為時,例如:日志記錄、權限驗證、事務管理、訪問統計等公共行為,這樣不便于維護,而且有大量重復代碼,AOP 可以實現和 AOP 的互補。
舉個例子: 我們有兩個邏輯登錄業務、訂單業務,需要在他們調用前后進行:權限驗證、日志記錄等公共邏輯。
- 通過 OOP 的方式實現我們需要做一個邏輯模板:權限驗證,具體邏輯(登錄、訂單),日志記錄。
- 通過 AOP 的方式實現我們只需針對具體邏輯(登錄、訂單)前后做一個自定義切點,進行權限驗證、日志記錄。
如下圖:
經過 AOP 方式處理過后,我們可以減少公共對象的引用、通過非繼承的方式來處理切入邏輯的攔截,實現公共邏輯和業務的邏輯的松耦合關系。
AOP 實現
Spring 通過代理的方式去實現 AOP,Java 代理的兩種模式:靜態代理、動態代理。
- 靜態代理:靜態代理是指在程序運行前,可以理解為是 .java 文件編譯后就存在代理類的字節碼 .class 文件。
- 動態代理:動態代理指在程序運行期間通過 JVM 反射等動態機制,在運行期生成代理對象確定代理邏輯。
Spring 的兩種代理模式:
- JDK 代理:核心類JdkDynamicAopProxy。
- GCLIB 代理:核心類ObjenesisCglibAopProxy。
兩種代理的選擇:如果 Bean 實現了接口就采用 JDK 代理, 如果沒有實現就采用 GCLIB 代理。
AOP 使用
假設已經有一個 UserService 類提供了登錄業務,我們需要對該業務做一個【權限驗證】、【日志記錄】這兩個公共邏輯,在不修改 UserService 類代碼的前提下就可以通過 AOP 來解決。示例如下:
maven 依賴
參考文檔
- Spring 官方文檔
- 駱駝整理說-Spring AOP
- Java-為什么使用Spring框架