面試前突擊Spring,我只需要十分鐘

前言

作爲一個寫Java的程序員,應該不太可能沒聽過Spring。對開發者來說,Spring就像是哆啦A夢的口袋。無論需要什麼道具,都可以從口袋裏直接拿出來,而不用關心這些道具來自哪裏。

本篇主要記錄一些關於Spring的基礎知識,用於快速查找和回顧不適合作爲Spring的入門學習(頭鐵的旁友隨意)。

核心

Spring的兩大核心當屬IOCAOP

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容器注入所依賴類型的對象。
  • 依賴查找:依賴查找是容器中的對象,通過容器的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環境。

注入方式

屬性的注入有兩種方式:byTypebyName

  • byType:如果容器中存在一個與指定屬性類型相同的bean,那麼將該屬性自動裝配。
    比如在Controller注入Service
    private IUserService userService
    
    byType方式會自動注入IUserService的實現類UserServiceImpl,如果實現類有多個,默認會拋出異常。下文講述如何解決。
  • byName:通過屬性名稱自動裝配。
    比如在Controller注入Service
    private IUserService userService
    
    通過byName的方式需要指定實現類UserServiceImplName
    @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的生命週期頗爲複雜,以下是整個過程
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/jsonapplication/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-mvc請求過程

總結

本篇主要列舉了與Spring相關的一些基礎知識,包括IOC、AOP、bean的作用域、生命週期、事務傳播機制、常用註解等。瞭解了這些基礎知識,能幫助我們更好的使用Spring。

一時沒想起來的基礎知識,後續還會補充。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章