天天看點

SpringBoot - 實踐阿裡巴巴【Manager 層_通用業務處理層】

文章目錄

  • ​​規範​​
  • ​​對比傳統MVC​​
  • ​​小栗子​​
  • ​​V1.0 傳統寫法​​
  • ​​V2.0 引入Manager層​​
  • ​​源碼​​
SpringBoot - 實踐阿裡巴巴【Manager 層_通用業務處理層】

規範

SpringBoot - 實踐阿裡巴巴【Manager 層_通用業務處理層】
SpringBoot - 實踐阿裡巴巴【Manager 層_通用業務處理層】

對比傳統MVC

說幾個弊端

  • Service層代碼臃腫
  • Service層易出現大事務,事務嵌套,易出問題且難排查
  • dao層混雜業務邏輯
  • dao層sql語句複雜

為了解決這個問題,《阿裡巴巴泰山版java開發手冊》推薦在Service層之下獨立出一個通用業務處理層(Manager層)

SpringBoot - 實踐阿裡巴巴【Manager 層_通用業務處理層】

相比較傳統的MVC,主要增加了 Manager 層, 它有如下特征:

  • 1) 對第三方平台封裝的層,預處理傳回結果及轉化異常資訊
  • 2) 對 Service 層通用能力的下沉,如緩存方案、中間件通用處理
  • 3) 與 DAO 層互動,對多個 DAO 的組合複用

實際開發中,

  • 對于複雜業務,service調用manager層,然後把​事務下沉到Manager層​,Manager層不允許互相調用,不會出現事務嵌套。
  • 專注于不帶業務SQL,也可以在manager層進行通用業務的dao層封裝。
  • 避免複雜的join查詢,可以在manager層嚴格控制好SQL,應對複雜的SQL查詢。

簡言之, Manager 層提供原子服務接口,Service 層負責依據業務邏輯來調用原子接口。

SpringBoot - 實踐阿裡巴巴【Manager 層_通用業務處理層】

小栗子

舉個例子說明一下Manager層的使用場景

需求:

  1. APP 登入的使用者,如果系統中沒有使用者,需要自動建立使用者,然後再傳回相關的使用者資訊用于展示
  2. 網頁端登陸的使用者,如果系統中沒有使用者,不自動建立使用者,需要使用者注冊。
SpringBoot - 實踐阿裡巴巴【Manager 層_通用業務處理層】

反手就是一頓突突啊

V1.0 傳統寫法

package com.artisan.service;

import com.artisan.dao.UserDao;
import com.artisan.response.ResponseData;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.concurrent.TimeUnit;

/**
 * @author 小工匠
 * @version 1.0
 * @mark: show me the code , change the world
 */


@Service
public class ServiceWithoutManager {

    private final boolean APP = true;

    @Autowired
    private UserDao userDao;

    @Transactional(rollbackFor = Throwable.class)
    public ResponseData<String> buiz(Long idCard, Long name) {

        // 驗證 1  假設  DB操作 校驗
        String  var1 = doDBCheck1();

        // 驗證 2  假設  DB操作 校驗
        String  var2 =  doDBCheck2();

        // 業務  APP -- DB校驗 --- 自動建立使用者 -- 傳回使用者資訊
        //      網頁 -- DB校驗 ---  -- 傳回使用者資訊
        doBiz(var1,var2);

        return ResponseData.success("success");
    }

    @SneakyThrows
    private void doBiz(String a ,String b) {
        if(APP) {
            // 模拟業務耗時
            TimeUnit.MILLISECONDS.sleep(1200);
        }else {

        }
    }

    @SneakyThrows
    private String doDBCheck2() {
        // 模拟業務耗時
        TimeUnit.MILLISECONDS.sleep(500);
        return "";
    }

    @SneakyThrows
    private String doDBCheck1() {
        // 模拟業務耗時
        TimeUnit.MILLISECONDS.sleep(1000);
        return "";
    }


}      
SpringBoot - 實踐阿裡巴巴【Manager 層_通用業務處理層】

這有啥子問題? 正常操作啊…

每日一博 - 常見的Spring事務失效&事務不復原案例集錦

讓我們來分析分析

  • 典型的長事務問題 , 由于方法上有@Transactional 注解,是以驗證和業務都是使用的同一個 connection
  • 對于複雜業務、複雜的驗證邏輯,會導緻整個驗證過程始終占用該 connection 連接配接,占用時間可能會很長,直至方法結束,connection 才會交還給資料庫連接配接池。

對于複雜業務的不可預計的情況,長時間占用同一個 connection 連接配接應該盡量避免,應該盡量縮短占用時間。

SpringBoot - 實踐阿裡巴巴【Manager 層_通用業務處理層】

@Transactional 注解, AOP 實作,本質就是在目标方法執行前後進行攔截。 在目标方法執行前加入或建立一個事務,在執行方法執行後,根據實際情況選擇送出或是復原事務。

當 Spring 遇到該注解時,會自動從資料庫連接配接池中擷取 connection,并開啟事務然後綁定到 ThreadLocal 上,對于@Transactional注解包裹的整個方法都是使用同一個connection連接配接。

如果出現了耗時的操作,比如三方接口調用,業務邏輯複雜,大資料處理等就會導緻占用這個connection的時間過長,資料庫連接配接一直被占用不釋放。一旦類似操作過多,進而導​緻資料庫連接配接池耗盡。​

SpringBoot - 實踐阿裡巴巴【Manager 層_通用業務處理層】

V2.0 引入Manager層

SpringBoot - 實踐阿裡巴巴【Manager 層_通用業務處理層】
SpringBoot - 實踐阿裡巴巴【Manager 層_通用業務處理層】

将資料在 service 層準備好,然後傳遞給 manager 層,由 manager 層添加@Transactional事務注解進行資料庫操作, 盡量減少大事務帶來的危害。

SpringBoot - 實踐阿裡巴巴【Manager 層_通用業務處理層】

源碼

​​https://github.com/yangshangwei/boot2​​

繼續閱讀