前言
作爲一個寫Java的程序員,應該不太可能沒聽過Spring。對開發者來說,Spring就像是哆啦A夢的口袋。無論需要什麼道具,都可以從口袋裏直接拿出來,而不用關心這些道具來自哪裏。
本篇主要記錄一些關於Spring的基礎知識,用於快速查找和回顧,不適合作爲Spring的入門學習(頭鐵的旁友隨意)。
核心
Spring的兩大核心當屬IOC和AOP。
IOC
IOC是控制反轉(Inversion Of Control),IOC是一種編程思想。Spring的IOC容器實現了IOC,是Spring框架的基本功能,管理着Spring應用中bean的創建、配置和管理。Spring的IOC容器接管了應用中的bean,能夠自動解決bean與bean之間的依賴。對使用者來說就像是一個黑盒,不需要關心bean之間的依賴是怎樣的,大大減少了編程的難度。
IOC的實現方式有兩種:依賴注入(Dependency Injection,DI)和依賴查找(Dependency Lookup,DL)
- 依賴注入:應用程序被動的接收對象,bean實例化的時候,IOC容器會自動根據類型或者名稱,把依賴的其他bean注入給當前bean。依賴注入的方式主要有以下四種:
- 註解:通過註解來讓IOC容器注入所依賴類型的對象,例如最常用的
@Autowired
。 - 構造方法:實現對應參數的構造方法,在創建對象時來讓IOC容器注入所依賴類型的對象。
setter
方法:實現對應屬性的setter
方法,來讓IOC容器注入所依賴類型的對象。- 接口:實現特定接口以,讓IOC容器注入所依賴類型的對象。
- 註解:通過註解來讓IOC容器注入所依賴類型的對象,例如最常用的
- 依賴查找:依賴查找是容器中的對象,通過容器的API,來查找自己所依賴的資源和對象。相比於依賴注入,依賴查找是一種更加主動的方式。
AOP
AOP(Aspect-Oriented Programming)即面向切面編程,是一種完全不同於OOP的編程思想。AOP不是用來取代OOP的,反而是來補充OOP的。
OOP的思想把項目分爲層次結構,是一種從上到下的結構。這種上下結構想要做到從左到右是一件非常繁瑣的事。這種從左到右的需求往往是一些諸如日誌、安全、事務等,非業務性的功能。這樣的功能如果按照OOP的思想來實現,就會導致大量冗餘、侵入性強的代碼。所以AOP的作用就是剝離一些非業務代碼,做到統一管理。
AOP的功能就是在運行時,把指定的代碼動態的加入到指定的地方,來完成一些非業務邏輯的功能,從而避免手動編寫這些代碼。
AOP往往採用動態代理的方式來實現。
作用域
Spring bean的作用域主要有五種:
singleton
:在整個Spring IoC容器僅存在一個Bean實例,Bean以單例方式存在。singleton
是Spring的默認配置。prototype
:每次從Spring IoC容器中獲取Bean時,都返回一個新的實例。request
:每次HTTP請求都會創建一個新的Bean實例。該作用域僅適用於Spring構建的web環境。session
:同一個HTTP Session共享一個Bean,不同Session使用不同的Bean。該作用域僅適用於Spring構建的web環境。application
:限定一個Bean的作用域爲整個web應用。該作用域僅適用於Spring構建的web環境。
注入方式
屬性的注入有兩種方式:byType
和byName
。
byType
:如果容器中存在一個與指定屬性類型相同的bean,那麼將該屬性自動裝配。
比如在Controller
注入Service
private IUserService userService
byType
方式會自動注入IUserService
的實現類UserServiceImpl
,如果實現類有多個,默認會拋出異常。下文講述如何解決。byName
:通過屬性名稱自動裝配。
比如在Controller
注入Service
通過private IUserService userService
byName
的方式需要指定實現類UserServiceImpl
的Name@Service("userService") public class UserServiceImpl implements IUserService {...}
事務隔離級別
Spring提供了五種隔離級別:
DEFAULT
(默認):意思就是數據庫用啥我用啥SERIALIZABLE
(串行化):事務之間以一種串行的方式執行REPEATABLE READ
(可重複讀):是MySQL默認的隔離級別,同一個事務中相同的查詢會看到同樣的數據行READ COMMITED
(讀已提交):一個事務可以讀到另一個事務已經提交的數據READ UNCOMMITED
(讀未提交):一個事務可以讀到另一個事務未提交的數據
除了第一個是Spring新增的,其餘的四個都是和數據庫的事務隔離級別一一對應。不瞭解數據庫事務隔離級別的旁友翻下這篇:面試官:MySQL事務是怎麼實現的
事務傳播機制
事務傳播機制是指在一個可能含有事務的方法中,調用了另一個可能含有事務的方法,這兩個事務應該如何去取捨。最常見的場景就是在Service層。比如OrderService#createOrder()
方法裏調用了StockService#decreaseStock()
,而這兩個方法明顯都是有事務的。這時,兩個事務如何相互影響就是事務傳播機制。
Spring提供了七種事務傳播機制:
REQUIRED
:Spring默認值,如果事務已經開啓,則加入當前事務;如果沒有事務,則開啓一個新的事務。MANDATORY
:如果事務已經開啓,則加入當前事務;如果沒有事務,就拋出異常。NEVER
:以非事務方式執行,如果當前存在事務,則拋出異常。NOT_SUPPORTED
:以非事務方式執行操作,如果當前存在事務,就把當前事務掛起。REQUIRES_NEW
:新建事務,如果當前存在事務,把當前事務掛起。SUPPORTS
:支持當前事務,如果當前沒有事務,就以非事務方式執行。NESTED
:支持當前事務,新增Savepoint,與當前事務同步提交或回滾。外層事務失敗時,會回滾內層事務所做的動作。而內層事務操作失敗並不會引起外層事務的回滾。
生命週期
Spring管理了對象的生命週期,所以有必要了解Spring到底是怎麼管理bean的生命週期的。如果我們想要在bean生命週期的某個時刻執行特定的功能應該怎麼辦?
Spring bean的生命週期頗爲複雜,以下是整個過程
常用註解
標識類
@Component
:標識此類由Spring IOC容器管理@Controller
:標識此類是接收和轉發請求用的Controller
類,是@Component
的細化註解@Service
:標識此類是處理業務邏輯的Service
類,是@Component
的細化註解@Repository
:標識此類是處理持久化操作相關的類,通常是XxxDao
,是@Component
的細化註解
注入類
@Autowired
:屬於Spring,是根據類型(byType
)的方式自動注入屬性,默認是必須的。如果要設置成可選,需要把required
設置成false
如果@Autowired(required = false) private IUserService userService;
IUserService
的實現類不止一個,默認會報錯。需要配合註解@Qualifier
指定具體的實現類
正確注入方式public interface IUserService { } @Component("helloUserService") public class HelloUserServiceImpl implements IUserService { } @Component("worldUserService") public class WorldUserServiceImpl implements IUserService { }
@Autowired @Qualifier("helloUserService") private IUserService userService;
@Qualifier
:見@Autowired
@Resource
屬於JDK,默認是按照名稱(byName
)進行裝配的。- 如果沒有指定
name
屬性,默認取字段的名稱作爲bean名稱尋找依賴對象。 - 如果沒有指定
name
屬性,且byName
的方式無法裝配,則會按照byType
的方式進行裝配。 - 如果僅指定的
type
屬性,也會通過byType
的方式進行裝配,找不到或者找到多個都會拋異常。 - 只要指定了
name
屬性,就不會再按照byType
的方式進行裝配。
- 如果沒有指定
@Value
:用於注入一些配置文件中的常量,如jdbc相關的配置等
web相關
-
@RequestMapping
:這個註解會將HTTP請求映射到Controller
的處理方法上。// 簡單用法 @RequestMapping("/index") // 映射多個url @RequestMapping({"/index", "/home"}) // 限制請求方式爲Post,等同於註解 @PostMapping("/index") @RequestMapping(value = "/index", method = RequestMethod.POST)
-
@RequestBody
:將HTTP請求正文插入方法中,用來處理請求的Content-Type
不是application/x-www-form-urlencoded
(表單)編碼的內容,例如:application/json
、application/xml
等。也就是說當客戶端向後臺提交數據不是以表單,而是以JSON數據的方式時,可以使用@RequestBody
註解將數據映射到後臺參數列表// 前端 $.ajax({ type: 'POST', dataType: "json", contentType: "application/json; charset=utf-8", data: JSON.stringify(paramJson), url: "", success: function (data) { } }); // 後臺 @RequestMapping("/xxx") public Sring xxx(@RequestBody UserDTO userDTO) { return "success"; }
-
@RequestParam
:用來輔助綁定特殊要求的參數// 表示該接口必須傳遞參數id @RequestMapping("/xxx") public String xxx(@RequestParam("id") String id) { return ""; } // 參數id可以不傳 @RequestMapping("/xxx") public String xxx(@RequestParam(name = "id", required = false) String id) { return "success"; }
-
@PathVariable
:表示將url中的參數變量綁定到參數列表// 將參數列表中的值自動填充到url中的變量中 @RequestMapping("/order/{orderId}") public String xxx(@PathVariable String orderId) { return "success"; } // 如果參數列表中的參數名和url中的不一致,則需要指定@PathVariable的name屬性 @RequestMapping("/order/{orderId}") public String xxx(@PathVariable(name = "orderId") String id) { return "success"; }
-
@ResponseBody
:表示該方法的返回的結果直接寫入 HTTP 響應正文中,而不是跳轉到某個路徑,一般用於向客戶端返回JSON數據。// 把success字符串返回給客戶端 @ResponseBody @RequestMapping("/xxx") public String xxx() { return "success"; }
SpringMVC請求過程
一圖勝千言
總結
本篇主要列舉了與Spring相關的一些基礎知識,包括IOC、AOP、bean的作用域、生命週期、事務傳播機制、常用註解等。瞭解了這些基礎知識,能幫助我們更好的使用Spring。
一時沒想起來的基礎知識,後續還會補充。