精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

DDD架構(gòu)下的防御式編程:五大關(guān)卡共同保障業(yè)務(wù)數(shù)據(jù)的有效性

開(kāi)發(fā) 架構(gòu)
一般情況下,在流程達(dá)到存儲(chǔ)引擎前,所有的驗(yàn)證規(guī)則必須全部通過(guò),盡量不要使用存儲(chǔ)引擎作為兜底方案。但有一種情況極為特殊,也就只有存儲(chǔ)引擎能夠優(yōu)雅的完成,那就是唯一鍵保護(hù)。

1. 規(guī)則驗(yàn)證是準(zhǔn)確性的基礎(chǔ)

規(guī)則驗(yàn)證是業(yè)務(wù)穩(wěn)定性的重要保障手段,通過(guò)規(guī)則驗(yàn)證,可以驗(yàn)證和確保系統(tǒng)或業(yè)務(wù)邏輯的正確性和合規(guī)性,避免潛在的錯(cuò)誤和問(wèn)題。而規(guī)則的遺漏往往會(huì)伴隨著線上bug的出現(xiàn)。

相信每個(gè)開(kāi)發(fā)人員都曾面對(duì)過(guò)以下情況:

  1. 未對(duì)入?yún)⑦M(jìn)行非空判斷,在執(zhí)行邏輯時(shí)導(dǎo)致空指針異常(NullPointerException,簡(jiǎn)稱NPE);
  2. 未正確驗(yàn)證用戶權(quán)限,導(dǎo)致未授權(quán)操作發(fā)生,普通用戶也能執(zhí)行該操作,最終產(chǎn)生安全問(wèn)題;
  3. 在數(shù)據(jù)被存儲(chǔ)到數(shù)據(jù)庫(kù)時(shí),沒(méi)有進(jìn)行完整性驗(yàn)證,導(dǎo)致無(wú)效數(shù)據(jù)被存儲(chǔ);
  4. 在業(yè)務(wù)邏輯中,未對(duì)可能拋出的異常進(jìn)行適當(dāng)?shù)奶幚?,?dǎo)致系統(tǒng)無(wú)法正常運(yùn)行;

可見(jiàn),驗(yàn)證對(duì)流程極為重要,不合理的輸入會(huì)導(dǎo)致嚴(yán)重的業(yè)務(wù)問(wèn)題。同時(shí)錯(cuò)誤數(shù)據(jù)的影響也比想象中的大得多:

  1. 可能會(huì)導(dǎo)致整個(gè)寫(xiě)流程異常中斷;
  2. 錯(cuò)誤數(shù)據(jù)入庫(kù)后,會(huì)對(duì)所有的讀操作造成致命的傷害;
  3. 上游系統(tǒng)數(shù)據(jù)錯(cuò)誤,下游系統(tǒng)紛紛“崩潰”;

2. 防御式編程

如何避免上述情況的發(fā)生,答案就在 防御式編程。

防御式編程(Defensive Programming)是一種軟件開(kāi)發(fā)方法,目的是在代碼中預(yù)測(cè)可能出現(xiàn)的異常和錯(cuò)誤情況,并用適當(dāng)?shù)拇胧?duì)其進(jìn)行處理,從而提高軟件的健壯性和穩(wěn)定性。通過(guò)防御式編程,軟件開(kāi)發(fā)人員可以在軟件功能相對(duì)復(fù)雜的情況下,避免和減少由于程序錯(cuò)誤所導(dǎo)致的不可預(yù)測(cè)的行為和不良影響,并保障軟件在部署和運(yùn)行時(shí)的正確性和穩(wěn)定性,提高軟件可靠性和安全性。

防御式編程的核心思想是在代碼中盡量考慮一切可能出現(xiàn)的異常和錯(cuò)誤情況,并在代碼中針對(duì)這些異常和錯(cuò)誤情況做出相應(yīng)的處理。例如,可以使用異常捕獲機(jī)制處理可能出現(xiàn)的異常,充分利用代碼注釋和約束條件來(lái)規(guī)范輸入數(shù)據(jù),使用斷言(assert)來(lái)檢查代碼中的前置條件和后置條件等。

概念過(guò)于繁瑣,簡(jiǎn)單理解:防御式編程就是:

  1. 不要相信任何輸入,在正式使用前,必須保證參數(shù)的有效性;
  2. 不相信任何處理邏輯,在流程處理后,必須保證業(yè)務(wù)規(guī)則仍舊有效;

對(duì)輸入?yún)?shù)保持懷疑,對(duì)業(yè)務(wù)執(zhí)行的前提條件保存懷疑,對(duì)業(yè)務(wù)執(zhí)行結(jié)果保持懷疑,將極大的提升系統(tǒng)的準(zhǔn)確性!

3. 異常中斷還是返回值中斷?

在規(guī)則校驗(yàn)場(chǎng)景,優(yōu)先使用異常進(jìn)行流程中斷。

3.1. 異常中斷才是標(biāo)配

在沒(méi)有提供異常的編程語(yǔ)言中,我們只能使用特殊返回值來(lái)表示異常,這樣的設(shè)計(jì)會(huì)將正常流程和異常處理流程混在一起,讓語(yǔ)言失去了可讀性。比如在 C 中,通用會(huì)使用 -1 或 NULL 來(lái)表示異常情況,所以在調(diào)用函數(shù)第一件事便是判斷 result 是 NULL 或 -1,比如以下代碼:

void readFileAndPrintContent(const char* filename) {
    FILE* file = fopen(filename, "r");
    if (file == NULL) {
        // 文件無(wú)法打開(kāi),返回異常狀態(tài)
        fprintf(stderr, "Failed to open the file.\n");
        return;  // 直接返回,表示發(fā)生異常
    }

    char line[256];
    while (fgets(line, sizeof(line), file) != NULL) {
        printf("%s", line);
    }

    fclose(file);
}

在 Java 語(yǔ)言中,引入了完整的異常機(jī)制,以更好的處理異常情況,該機(jī)制有如下特點(diǎn):

  1. 邏輯分離,將正常處理和異常處理進(jìn)行分離。異常機(jī)制可以將錯(cuò)誤處理代碼從正常業(yè)務(wù)邏輯中分離出來(lái),使得代碼更加清晰和易讀。同時(shí),可以將異常處理代碼集中在一起,便于理解和維護(hù);
  2. 異常傳播和捕獲。當(dāng)異常在方法中被拋出時(shí),可以選擇在當(dāng)前方法中捕獲并處理異常,或者將異常繼續(xù)傳播給調(diào)用者,直到找到合適的異常處理器。這種靈活的異常傳播機(jī)制使得錯(cuò)誤可以被適當(dāng)?shù)靥幚恚粫?huì)造成程序的中斷;
  3. 異常信息傳遞。在異常對(duì)象中,Java 提供了豐富的信息用于描述異常的發(fā)生原因和上下文。包括異常類(lèi)別、異常消息、異常發(fā)生的位置等。這些信息可以幫助開(kāi)發(fā)人員快速定位和修復(fù)異常,提高代碼的調(diào)試和維護(hù)效率;

在 Java 中異常處理變得簡(jiǎn)單且嚴(yán)謹(jǐn):

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class FileReadExample {
    public static void readFileAndPrintContent(String filename) throws IOException {
        try (BufferedReader reader = new BufferedReader(new FileReader(filename))) {
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
        } 
    }

    public static void main(String[] args) {
        try {
            readFileAndPrintContent("example.txt");
        } catch (IOException e) {
            System.err.println("Exception occurred: " + e.getMessage());
            System.exit(-1);  // 返回錯(cuò)誤代碼 -1 表示發(fā)生異常
        }
    }
}

在日常業(yè)務(wù)開(kāi)發(fā)中,當(dāng)出現(xiàn)不符合業(yè)務(wù)預(yù)期時(shí),直接通過(guò)異常對(duì)流程進(jìn)行中斷即可。

3.2. 立即中斷還是階段中斷?

當(dāng)出現(xiàn)不符合預(yù)期情況時(shí),是直接拋出異常,還是完成整個(gè)階段在拋出異常?這個(gè)需要看業(yè)務(wù)場(chǎng)景!

參數(shù)驗(yàn)證場(chǎng)景,需要對(duì)所有不合法信息進(jìn)行收集,然后統(tǒng)一拋出異常,從而能夠讓用戶一目了然的看到所有問(wèn)題信息,以方便進(jìn)行統(tǒng)一修改。

而在業(yè)務(wù)場(chǎng)景,不符合規(guī)則時(shí),需要直接進(jìn)行異常中斷,避免對(duì)后續(xù)流程造成破壞。

4. 標(biāo)準(zhǔn)寫(xiě)流程中的規(guī)則驗(yàn)證

使用 DDD 進(jìn)行開(kāi)發(fā)時(shí),一個(gè)標(biāo)準(zhǔn)的寫(xiě)流程包括:

圖片圖片

其中,涉及5大類(lèi)規(guī)則驗(yàn)證,如:

  1. 參數(shù)校驗(yàn)。對(duì)入?yún)⑦M(jìn)行基本校驗(yàn),比如是否為null、類(lèi)型是否匹配等;
  2. 業(yè)務(wù)校驗(yàn)。特指對(duì)前置業(yè)務(wù)規(guī)則或資源的校驗(yàn),比如庫(kù)存是否足夠、商品狀態(tài)是否可售等;
  3. 狀態(tài)校驗(yàn)。特指聚合內(nèi)狀態(tài)校驗(yàn),核心為業(yè)務(wù)狀態(tài)機(jī),比如只有訂單狀態(tài)為待支付時(shí),才能進(jìn)行支付成功操作;
  4. 固定規(guī)則校驗(yàn)。如果聚合內(nèi)有固定規(guī)則,在進(jìn)行持久化操作前,需對(duì)規(guī)則進(jìn)行驗(yàn)證,比如 訂單支付金額 = 所有商品售賣(mài)價(jià)格總和 - 各類(lèi)優(yōu)惠總和;
  5. 存儲(chǔ)引擎校驗(yàn)?;诖鎯?chǔ)引擎特性進(jìn)行的最后保障,比如在表中創(chuàng)建唯一索引,從而避免用戶的多次提交(冪等保護(hù));

4.1. 參數(shù)校驗(yàn)

這是最基礎(chǔ)的校驗(yàn),沒(méi)有太多的業(yè)務(wù)概念,只有簡(jiǎn)單的參數(shù)。其目的是 對(duì)數(shù)據(jù)格式進(jìn)行驗(yàn)證。

針對(duì)這種通用能力,優(yōu)先借助框架來(lái)完成,常用框架主要有:

  1. validation 框架。主要用于解決簡(jiǎn)單屬性的驗(yàn)證;
  2. Verifiable + AOP。主要用于多個(gè)屬性的驗(yàn)證;
4.1.1. Validation 框架

對(duì)于單屬性的驗(yàn)證,可以使用 hibernate validation 框架來(lái)實(shí)現(xiàn)。Hibernate Validation 是一個(gè)基于 Java Bean 驗(yàn)證規(guī)范(Java Bean Validation)的驗(yàn)證框架,它提供了一系列的特性來(lái)實(shí)現(xiàn)對(duì)數(shù)據(jù)模型的驗(yàn)證和約束,其特性主要包括:

  1. 提供了一組驗(yàn)證注解,用于在數(shù)據(jù)模型的字段、方法參數(shù)、返回值等地方添加驗(yàn)證約束。例如,@NotNull 用于驗(yàn)證字段不能為空,@Email 用于驗(yàn)證郵箱格式,@Size 用于驗(yàn)證字符串長(zhǎng)度等;
  2. 提供了許多內(nèi)置的驗(yàn)證注解,用于實(shí)現(xiàn)常見(jiàn)的驗(yàn)證需求。例如,@NotBlank 用于驗(yàn)證字符串非空且必須包含至少一個(gè)非空白字符,@Pattern 用于驗(yàn)證字符串匹配指定的正則表達(dá)式,@Min  @Max 用于驗(yàn)證數(shù)字的最小值和最大值等;
  3. 除了使用內(nèi)置的驗(yàn)證注解外,Hibernate Validation 還允許開(kāi)發(fā)者通過(guò)自定義約束注解來(lái)定義和應(yīng)用自定義的驗(yàn)證規(guī)則。通過(guò)創(chuàng)建自定義的約束注解,可以實(shí)現(xiàn)更加靈活和符合業(yè)務(wù)需求的驗(yàn)證規(guī)則;
  4. 允許將多個(gè)驗(yàn)證約束分組,并在需要時(shí)對(duì)特定的驗(yàn)證組進(jìn)行驗(yàn)證。這樣可以根據(jù)具體的場(chǎng)景選擇性地執(zhí)行驗(yàn)證操作,從而實(shí)現(xiàn)更加細(xì)粒度的驗(yàn)證控制;
  5. 提供了驗(yàn)證器和驗(yàn)證上下文等核心類(lèi),用于執(zhí)行驗(yàn)證操作和獲取驗(yàn)證結(jié)果。驗(yàn)證器負(fù)責(zé)執(zhí)行驗(yàn)證操作,而驗(yàn)證上下文提供了豐富的方法來(lái)獲取驗(yàn)證結(jié)果、獲取驗(yàn)證錯(cuò)誤信息等;
  6. 允許通過(guò)指定驗(yàn)證注解的驗(yàn)證順序,來(lái)控制驗(yàn)證的執(zhí)行順序。這樣可以確保在需要按順序執(zhí)行驗(yàn)證約束時(shí),每個(gè)約束都會(huì)按照指定的順序進(jìn)行驗(yàn)證;
  7. 支持國(guó)際化,可以根據(jù)不同的語(yǔ)言環(huán)境為驗(yàn)證錯(cuò)誤消息提供多語(yǔ)言支持。開(kāi)發(fā)者可以定義并配置驗(yàn)證錯(cuò)誤消息的資源文件,從而實(shí)現(xiàn)跨語(yǔ)言的驗(yàn)證錯(cuò)誤消息;

特性非常多,我們最常用的就是在模型字段、方法參數(shù)、返回值增加相應(yīng)功能的注解,比如在 CreateOrderCmd 中增加相關(guān)驗(yàn)證注解,從而避免手寫(xiě)代碼:

@Data
public class CreateOrderCmd {
    @NotNull
    private Long userId;

    @NotNull
    private Long productId;

    @NotNull
    @Min(1)
    private int count;
}
4.1.2. Verifiable +AOP

有些參數(shù)驗(yàn)證可能會(huì)比較復(fù)雜,需要對(duì)多個(gè)屬性進(jìn)行判斷,此時(shí) Validation 框架會(huì)顯得無(wú)能為力。

當(dāng)然,可以制定相應(yīng)規(guī)范,在參數(shù)封裝的類(lèi)上統(tǒng)一提供一個(gè) validate 方法,并在進(jìn)入方法后使用參數(shù)前調(diào)用該方法。但,規(guī)范由人執(zhí)行難免發(fā)生遺留。所以,最佳方案是將其內(nèi)化到框架。如下圖所示:

圖片圖片

image

  1. 首先,定義一個(gè)接口 Verifiable,該接口只有一個(gè) validate 方法;
  2. 其次,定義一個(gè) ValidateIntercepter 類(lèi),基于前置攔截器對(duì)入?yún)⑦M(jìn)行判斷,如果實(shí)現(xiàn) Verifiable 接口,則自動(dòng)調(diào)用 validate 方法;
  3. 最后,基于 AOP 技術(shù)生成 Proxy,從而完成統(tǒng)一的參數(shù)校驗(yàn);

當(dāng)需要對(duì)多個(gè)參數(shù)進(jìn)行校驗(yàn)時(shí),只需要實(shí)現(xiàn) Verifiable 接口的 validate 方法即可,無(wú)需手工對(duì) validate 進(jìn)行調(diào)用。

4.2. 業(yè)務(wù)校驗(yàn)

業(yè)務(wù)校驗(yàn)是業(yè)務(wù)邏輯執(zhí)行的前置條件驗(yàn)證,包括外部校驗(yàn)和控制條件校驗(yàn)。

通常情況下,業(yè)務(wù)校驗(yàn)比較復(fù)雜,變化頻次也比較高,所以對(duì)擴(kuò)展性要求很高。但,業(yè)務(wù)規(guī)則本身比較獨(dú)立,相互之間沒(méi)有太多的依賴關(guān)系。為了更好的應(yīng)對(duì)邏輯擴(kuò)展,可以使用策略模型進(jìn)行設(shè)計(jì)。如下圖所示:

圖片圖片

4.2.1. 業(yè)務(wù)驗(yàn)證器

業(yè)務(wù)驗(yàn)證器就是策略模型中的策略接口。

核心代碼如下:

public interface BaseValidator<A> extends SmartComponent<A> {
    void validate(A a, ValidateErrorHandler validateErrorHandler);

    default void validate(A a){
        validate(a, ((name, code, msg) -> {
            throw new ValidateException(name, code, msg);
        }));
    }
}

該接口非常簡(jiǎn)單:

  1. 提供統(tǒng)一的 validate 方法定義;
  2. 繼承自 SmartComponent,可以通過(guò) boolean support(A a) 來(lái)驗(yàn)證該組件是否能被處理;
4.2.2. 共享數(shù)據(jù) Context

有了統(tǒng)一的策略接口后,需要使用 Context 模式對(duì)入?yún)⑦M(jìn)行管理。Context 可以是簡(jiǎn)單的數(shù)據(jù)容器,也可以是一個(gè)具有 LazyLoad 能力的加強(qiáng)容器,其核心功能就是在多個(gè)策略間實(shí)現(xiàn)數(shù)據(jù)的共享。

比如,在生單流程中的 CreateOrderContext 定義如下:

@Data
public class CreateOrderContext implements CreateOrderContext{

    private CreateOrderCmd cmd;

    @LazyLoadBy("#{@userRepository.getById(cmd.userId)}")
    private User user;

    @LazyLoadBy("#{@productRepository.getById(cmd.productId)}")
    private Product product;

    @LazyLoadBy("#{@addressRepository.getDefaultAddressByUserId(user.id)}")
    private Address defAddress;

    @LazyLoadBy("#{@stockRepository.getByProductId(product.id)}")
    private Stock stock;

    @LazyLoadBy("#{@priceService.getByUserAndProduct(user.id, product.id)}")
    private Price price;
}

其中 @LazyLoadBy 是一個(gè)功能加強(qiáng)注解,在第一次訪問(wèn)屬性的 getter 方法時(shí),將自動(dòng)觸發(fā)數(shù)據(jù)加載,并將加載的數(shù)據(jù)設(shè)置到屬性上,再第二次訪問(wèn)時(shí),直接從屬性上獲取所需數(shù)據(jù)。

【注】對(duì)該部分感興趣,可以學(xué)習(xí) 《Command\&Query Object 與 Context 模式》

4.2.3. 策略類(lèi)管理

在有了策略接口 和 共享數(shù)據(jù) Context 后,接下來(lái)便是按照業(yè)務(wù)需求實(shí)現(xiàn)高內(nèi)聚低耦合的各種實(shí)現(xiàn)類(lèi)。如下圖所示:

圖片圖片

這些組件如何進(jìn)行管理,詳見(jiàn)下圖:

圖片圖片

  1. 首先,在啟動(dòng)時(shí),所有的 BusinessValidator 實(shí)例會(huì)被 Spring 注入到 ValidateService 中的 validators 集合;
  2. 在調(diào)用 validateBusiness 函數(shù)時(shí),依次遍歷 validators 集合,找到能處理該 Context 的 validator 實(shí)例并執(zhí)行對(duì)應(yīng)的 validate 方法;

這樣做最大的好處便是,在驗(yàn)證組件中徹底實(shí)現(xiàn)“開(kāi)閉原則”:

  1. 增加新的業(yè)務(wù)邏輯時(shí),只需增加一個(gè)新的 Spring 組件,系統(tǒng)將自動(dòng)完成集成;
  2. 在修改某個(gè)業(yè)務(wù)校驗(yàn)時(shí),只會(huì)更改一個(gè)類(lèi),對(duì)其他校驗(yàn)沒(méi)有影響;

認(rèn)真思考后,可能會(huì)發(fā)現(xiàn):這其實(shí)是責(zé)任鏈模式的一種變形。但,由于實(shí)現(xiàn)非常簡(jiǎn)單,在 Spring 框架中多次使用。

4.3. 狀態(tài)校驗(yàn)

狀態(tài)校驗(yàn)又成前置狀態(tài)驗(yàn)證,是業(yè)務(wù)規(guī)則中最重要的一部分。

核心實(shí)體通常會(huì)有一個(gè)狀態(tài)屬性,狀態(tài)屬性的這些值共同組成一個(gè)標(biāo)準(zhǔn)的狀態(tài)機(jī)。如下圖所示:

圖片圖片

這是一個(gè)訂單實(shí)體的狀態(tài)機(jī),定義了各狀態(tài)間的轉(zhuǎn)換關(guān)系,這是領(lǐng)域設(shè)計(jì)中最為重要的一部分。當(dāng)發(fā)生業(yè)務(wù)動(dòng)作時(shí),第一件事不是修改業(yè)務(wù)狀態(tài),而是判斷當(dāng)前狀態(tài)下是否可以進(jìn)行該操作。

比如,支付成功的核心業(yè)務(wù):

public void paySuccess(PayByIdSuccessCommand paySuccessCommand){
  if (getStatus() != OrderStatus.CREATED){
       throw new OrderStatusNotMatch();
   }

   this.setStatus(OrderStatus.PAID);

   PayRecord payRecord = PayRecord.create(paySuccessCommand.getChanel(), paySuccessCommand.getPrice());
   this.payRecords.add(payRecord);

   OrderPaySuccessEvent event = new OrderPaySuccessEvent(this);
   this.events.add(event);
}

在進(jìn)入邏輯處理前,先對(duì)狀態(tài)進(jìn)行判斷,只有 “已創(chuàng)建” 才能接收 支付成功操作,并將狀態(tài)轉(zhuǎn)換為 “已支付”。

4.4. 固定規(guī)則校驗(yàn)

固定規(guī)則校驗(yàn)使用場(chǎng)景不多,但其威力巨大,可以從根源上解決邏輯錯(cuò)誤。

在訂單實(shí)體上存在大量的金額操作,比如:

  1. 優(yōu)惠券。用戶使用優(yōu)惠券后,用戶支付金額需減去優(yōu)惠金額,同時(shí)優(yōu)惠金額也會(huì)均攤到不同的訂單項(xiàng)上;
  2. 優(yōu)惠活動(dòng)。和優(yōu)惠券對(duì)訂單的影響基本一致,但場(chǎng)景會(huì)更加復(fù)雜;
  3. 優(yōu)惠疊加。優(yōu)惠券和優(yōu)惠活動(dòng)一起使用,共同對(duì)訂單進(jìn)行修改;
  4. 手工改價(jià)。商家與用戶協(xié)商一致后,商家可以在后臺(tái)對(duì)訂單的金額進(jìn)行修改;

訂單金額發(fā)生變化后,更新字段很多,但無(wú)論如何變化都需要滿足一個(gè)公式:支付金額 = 售賣(mài)金額總和 - 優(yōu)惠金額總和。

我們可以基于這個(gè)公式,在業(yè)務(wù)操作之后、數(shù)據(jù)庫(kù)更新之前對(duì)規(guī)則進(jìn)行校驗(yàn),一旦規(guī)則不滿足則說(shuō)明處理邏輯出現(xiàn)問(wèn)題,直接拋出異常中斷處理流程。

4.4.1. JPA 支持

JPA 支持在數(shù)據(jù)保存或更新前對(duì)業(yè)務(wù)方法進(jìn)行回調(diào)。

我們可以使用 回調(diào)注解 或 實(shí)體監(jiān)聽(tīng)器 完成業(yè)務(wù)回調(diào)。

@PreUpdate
@PrePersist
public void checkBizRule(){
    // 進(jìn)行業(yè)務(wù)校驗(yàn)
}

checkBizRule 方法上增加 @PreUpdate 和 @PrePersist,在保存數(shù)據(jù)庫(kù)或更新數(shù)據(jù)庫(kù)之前,框架自動(dòng)對(duì) chekBizRule 方法進(jìn)行回調(diào),當(dāng)方法拋出異常,處理流程被強(qiáng)制中斷。

也可以使用 實(shí)體監(jiān)聽(tīng)器 進(jìn)行處理,如下例所示:

// 首先,定義一個(gè) OrderListenrer
public class OrderListener {
    @PrePersist
    public void preCreate(Order order) {
        order.checkBiz();
    }

    @PostPersist
    public void postCreate(Order order) {
        order.checkBiz();
    }
}

// 在 Order 實(shí)體上添加相關(guān)配置
@Data
@Entity
@Table
@Setter(AccessLevel.PRIVATE)
// 配置 OrderListener
@EntityListeners(OrderListener.class)
public class Order implements AggRoot<Long> {
    // 省略部分非關(guān)鍵代碼
    public void checkBizRule(){
        // 進(jìn)行業(yè)務(wù)校驗(yàn)
    }
}
4.4.2. MyBatis 支持

MyBatis 對(duì)實(shí)體的生命周期支持并沒(méi)有 JPA 中那么強(qiáng)大,但通過(guò) Intercepter 仍舊能實(shí)現(xiàn)該功能。具體操作如下:

首先,自定義 Intercepter,判斷參數(shù)并調(diào)用規(guī)則校驗(yàn)方法:

@Intercepts({
        @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})
})
public class EntityInterceptor implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        Object[] args = invocation.getArgs();
        MappedStatement statement = (MappedStatement) args[0];
        Object parameter = args[1];

        // 在這里可以對(duì)參數(shù)進(jìn)行判斷,并執(zhí)行相應(yīng)的操作
        if (parameter instanceof Order) {
            Order order = (Order) parameter;
            order.checkBizRule();
        }

        return invocation.proceed();
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
        // 可以在這里設(shè)置一些配置參數(shù)
    }
}

然后,在 mybatis-config.xml 配置文件中增加 Intercepter 的配置,具體如下:

<configuration>
    <!-- 其他配置 -->

    <plugins>
        <plugin interceptor="com.example.EntityInterceptor"/>
    </plugins>
</configuration>
4.4.3. 業(yè)務(wù)框架擴(kuò)展

Lego 框架對(duì)標(biāo)準(zhǔn) Command 處理流程進(jìn)行封裝,流程中對(duì)固定規(guī)則校驗(yàn)進(jìn)行了支持。如下圖所示:

圖片圖片

image

在標(biāo)準(zhǔn)寫(xiě)流程中的固定規(guī)則校驗(yàn)階段會(huì)自動(dòng)調(diào)用 ValidateService 中的 validateRule,整體結(jié)構(gòu)和 業(yè)務(wù)校驗(yàn)基本一致,在這里就不在贅述。其中:

  1. 存在一個(gè)默認(rèn)實(shí)現(xiàn) AggBasedRuleValidator,可以通過(guò)重寫(xiě)聚合根上的 validate 方法來(lái)實(shí)現(xiàn) JPA 和 MyBatis 同樣的效果;
  2. 也可以自定義自己的 RuleValidator,將實(shí)現(xiàn)類(lèi)注入到 Spring 容器即可完成與業(yè)務(wù)流程的集成;

4.5. 存儲(chǔ)引擎校驗(yàn)

存儲(chǔ)引擎提供了非常豐富的數(shù)據(jù)校驗(yàn),比如 Not Null,Length、Unique 等;

一般情況下,在流程達(dá)到存儲(chǔ)引擎前,所有的驗(yàn)證規(guī)則必須全部通過(guò),盡量不要使用存儲(chǔ)引擎作為兜底方案。但有一種情況極為特殊,也就只有存儲(chǔ)引擎能夠優(yōu)雅的完成,那就是唯一鍵保護(hù)。

比如,在需要冪等保護(hù)時(shí),我們通常將冪等鍵設(shè)置為唯一索引,從而保證不會(huì)出現(xiàn)重復(fù)提交的情況。

5. 小結(jié)

為了保證臟數(shù)據(jù)(不符合業(yè)務(wù)預(yù)期的數(shù)據(jù))不會(huì)進(jìn)入到系統(tǒng),我們將“防御式編程”思想用到了極致,在一個(gè)標(biāo)準(zhǔn)的寫(xiě)流程中共設(shè)立了5項(xiàng)關(guān)卡,從多維度多視角對(duì)數(shù)據(jù)進(jìn)行保障:

  1. 參數(shù)校驗(yàn)。不要相信任何的輸入信息,需要對(duì)系統(tǒng)輸入進(jìn)行嚴(yán)格校驗(yàn);
  2. 業(yè)務(wù)校驗(yàn)。業(yè)務(wù)操作往往會(huì)依賴一些前置條件,這些前置條件累加在一起甚至比核心操作還要復(fù)雜,如何提供相互隔離且可擴(kuò)展的設(shè)計(jì)便成了這個(gè)階段的核心;
  3. 狀態(tài)校驗(yàn)。對(duì)狀態(tài)機(jī)進(jìn)行保護(hù),任何操作都存在前置狀態(tài),在非法狀態(tài)下不允許執(zhí)行,這就是這個(gè)階段要解決的問(wèn)題;
  4. 固定規(guī)則校驗(yàn)。當(dāng)上層業(yè)務(wù)變化多且復(fù)雜時(shí),可能會(huì)對(duì)某些固定規(guī)則造成破壞,所以,在業(yè)務(wù)操作完成后、數(shù)據(jù)操作之前,可以再次對(duì)固定規(guī)則進(jìn)行驗(yàn)證;
  5. 存儲(chǔ)引擎校驗(yàn)。校驗(yàn)優(yōu)先在Java 代碼中完成,不要將存儲(chǔ)引擎校驗(yàn)作為常態(tài)校驗(yàn)。但,在唯一性保障方面,存儲(chǔ)引擎是最簡(jiǎn)單最有效的策略;

5大關(guān)卡共同發(fā)力才能真正保障業(yè)務(wù)數(shù)據(jù)的有效性。

責(zé)任編輯:武曉燕 來(lái)源: geekhalo
相關(guān)推薦

2023-12-04 07:41:58

架構(gòu)防御式編程

2021-02-09 09:48:43

AR技術(shù)人工智能

2016-02-24 16:52:46

企業(yè)IT方案

2020-05-13 13:09:21

微隔離網(wǎng)絡(luò)攻擊網(wǎng)絡(luò)安全

2015-12-18 16:57:06

2016-07-26 11:21:53

2017-10-12 13:07:36

數(shù)據(jù)中心企業(yè)網(wǎng)絡(luò)

2023-09-20 17:20:46

增強(qiáng)現(xiàn)實(shí)ARVR

2017-01-15 18:15:23

2022-01-24 08:00:00

元宇宙數(shù)字環(huán)境技術(shù)

2011-05-27 15:16:37

網(wǎng)站跳出率

2014-12-18 09:43:50

云計(jì)算云計(jì)算技術(shù)

2012-12-27 08:57:30

CA TechnoloIT管理IT運(yùn)營(yíng)

2012-12-26 14:40:05

IT運(yùn)維企業(yè)管理

2022-04-15 10:02:42

網(wǎng)絡(luò)安全

2010-03-10 19:36:08

Python djan

2023-12-29 18:18:56

2024-07-23 15:15:26

2024-06-20 13:13:36

2019-09-18 20:28:26

大數(shù)據(jù)數(shù)據(jù)處理數(shù)據(jù)采集
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

精品久久久久久中文字幕动漫| 久久天天躁狠狠躁夜夜av| 久久久噜噜噜www成人网| 九色在线观看| 国产在线精品不卡| 97精品视频在线观看| 90岁老太婆乱淫| 亚洲精品66| 亚洲va国产天堂va久久en| 日本黑人久久| www.99视频| 久久精品一区二区国产| 久久精品中文字幕| 白丝女仆被免费网站| 国产精品亚洲欧美一级在线| 午夜精品久久久久影视| 色之综合天天综合色天天棕色| 国产三级精品在线观看| 久久福利精品| 精品综合久久久久久97| xxxxx在线观看| 综合中文字幕| 欧美日韩综合色| 18禁网站免费无遮挡无码中文| 在线免费观看黄色网址| av一本久道久久综合久久鬼色| 国产精品香蕉在线观看| 色网站在线播放| 视频在线不卡免费观看| 亚洲久久久久久久久久| 欧美色图校园春色| 国产麻豆一区| 日韩欧美一区二区三区| 日韩免费在线观看av| 日本激情视频在线观看| 国产日韩欧美综合在线| 九色综合日本| 欧美性猛交 xxxx| 激情国产一区二区| 国产精品中文在线| 黄瓜视频在线免费观看| 在线日韩视频| 久久精品国产2020观看福利| 人妻精品久久久久中文| 妖精视频一区二区三区 | 性色av免费观看| 亚洲视频观看| 欧美乱大交xxxxx另类电影| 91导航在线观看| 欧美禁忌电影网| 日韩国产精品视频| 这里只有精品在线观看视频| 综合成人在线| 欧美mv日韩mv国产| 国产ts在线观看| 亚洲精品在线国产| 日韩久久精品一区| 国产精久久久久| 综合中文字幕| 亚洲成色999久久网站| 久久人妻少妇嫩草av蜜桃| 日韩欧美高清一区二区三区| 日韩一区二区精品葵司在线 | 性感美女一区二区在线观看| 午夜不卡av在线| 国产精品一区二区免费在线观看| av在线最新| 日韩欧美在线网址| 欧美日韩大尺度| 91欧美精品| 欧美日本一区二区三区四区| 中文字幕免费高清在线| 色狠狠一区二区三区| 欧美高清性hdvideosex| 欧美一级免费在线| 综合久久成人| 亚洲欧美第一页| 国产伦理片在线观看| 日韩aaaa| 欧美裸体xxxx极品少妇| 日韩免费一二三区| 久久久人人人| 国产一区二区香蕉| 亚洲经典一区二区三区| 99精品久久久久久| 亚洲国产精品综合| 亚洲羞羞网站| 色综合天天综合给合国产| 三级a三级三级三级a十八发禁止| 亚洲美女色播| 欧美精品一区二区三区在线| 国产激情在线免费观看| 欧美大片aaaa| 国内精品久久久久久久| 日本黄色中文字幕| 国产在线精品一区在线观看麻豆| 国产精品久久久久久久久婷婷| 肉丝一区二区| 亚洲日本一区二区| av动漫免费看| 国产精品免费精品自在线观看 | 美女日批在线观看| 中文有码一区| 欧美贵妇videos办公室| 欧美一级淫片免费视频黄| 国产一区二区三区在线观看免费视频| 国产精品久久亚洲7777| www日韩tube| 亚洲福利一二三区| 黄色一级片免费的| 亚洲男人都懂第一日本| 久久中国妇女中文字幕| www.久久久久久久| 成人动漫一区二区在线| 亚洲永久一区二区三区在线| 国产99在线观看| 欧美三级中文字幕| 国产福利在线观看视频| 欧美淫片网站| 国产精品日韩在线一区| 日韩一二三四| 亚洲国产精品久久一线不卡| 国产喷水theporn| 亚洲精品小区久久久久久| 欧美巨乳美女视频| 91国内精品久久久| 久久精品视频在线看| 亚洲精品蜜桃久久久久久| 99综合99| 色av中文字幕一区| 超碰超碰超碰超碰| 成人激情免费电影网址| 丰满人妻一区二区三区53号| 国产成人精品一区二三区在线观看| 欧美精品一区二区三区视频| 小泽玛利亚一区二区免费| 免费一级欧美片在线观看| 免费av一区二区三区| 91福利区在线观看| 精品国产一区二区亚洲人成毛片 | 九热爱视频精品视频| 国内精品一区二区三区四区| a级片在线播放| 中文字幕亚洲一区二区va在线| 亚洲精品高清无码视频| 国产欧美日韩免费观看| 欧美孕妇性xx| 免费在线稳定资源站| 欧美午夜激情在线| 亚洲午夜久久久久久久久红桃| 亚洲东热激情| 国产欧美日韩伦理| 久久五月精品中文字幕| 精品蜜桃在线看| 国产亚洲欧美精品久久久www| 国产成人在线免费| 欧美日韩中文字幕在线播放| 天堂va在线高清一区| 欧美另类极品videosbest最新版本| 国产露脸91国语对白| 亚洲女与黑人做爰| 免费观看一区二区三区| 99精品国产福利在线观看免费| 国产伦精品一区二区三毛| freexxx性亚洲精品| 日韩精品福利网站| 天码人妻一区二区三区在线看| 久久综合国产精品| 国产又猛又黄的视频| 国产精品久久天天影视| 成人av资源网| 精品丝袜在线| 在线观看国产精品淫| 91国偷自产中文字幕久久| 亚洲黄色免费电影| 无码人妻aⅴ一区二区三区| 天堂精品中文字幕在线| 一区二区91美女张开腿让人桶| 国产成人免费av一区二区午夜| 欧美成人激情视频免费观看| 三级视频在线看| 色综合久久久久综合| 国产美女网站视频| 国产成人小视频| 日日橹狠狠爱欧美超碰| 成人激情诱惑| 成人国产1314www色视频| 成人免费观看在线观看| 正在播放亚洲1区| www.超碰在线.com| 欧美性猛交xxxx免费看漫画| 色偷偷男人天堂| 成人性生交大合| 亚洲综合在线网站| 国内精品福利| 午夜精品亚洲一区二区三区嫩草| 精品一级视频| 国产精品91久久久久久| 天堂av中文在线| 亚洲人成网站777色婷婷| 国产夫妻性生活视频| 欧美性猛交xxx| 久久国产波多野结衣| 99久久精品免费观看| 九色porny自拍| 国产日韩综合| 日本在线视频www色| 亚洲人成网亚洲欧洲无码| 亚洲aa中文字幕| 日韩中文视频| 91成人天堂久久成人| 国产传媒在线播放| 亚洲人成免费电影| 国模私拍视频在线| 欧美日韩日日骚| www亚洲视频| 亚洲电影第三页| av最新在线观看| 国产色产综合色产在线视频| 日韩黄色一区二区| 国产精品影视网| 欧美wwwwwww| 爽好久久久欧美精品| 国产免费黄色一级片| 91精品一区国产高清在线gif| 日本三级中国三级99人妇网站| 精品无人区一区二区| 91久久国产自产拍夜夜嗨| 欧美jizz18| 国产成人福利视频| jizz内谢中国亚洲jizz| 久久久久久久久国产| 1区2区在线观看| 精品国产网站地址| av在线电影免费观看| 亚洲免费一级电影| 亚洲欧美日韩综合在线| 亚洲的天堂在线中文字幕| 国产哺乳奶水91在线播放| 欧美日韩激情一区二区三区| 国产一级片免费视频| 欧美性少妇18aaaa视频| 日韩久久中文字幕| 欧美午夜精品久久久久久久| 韩国av中文字幕| 红桃av永久久久| 亚洲国产综合久久| 亚洲一区二区三区自拍| 精品小视频在线观看| 亚洲激情av在线| 国产亚洲自拍av| 亚洲国产欧美在线人成| 国产在线观看99| 午夜在线电影亚洲一区| 久久不卡免费视频| 狠狠久久五月精品中文字幕| 亚洲影院在线播放| 色老头久久综合| 国产精品无码粉嫩小泬| 欧美日韩综合在线免费观看| 91国偷自产中文字幕久久| 在线播放91灌醉迷j高跟美女| 国产精选久久久| 精品日韩一区二区| 全国男人的天堂网| 亚洲人成在线免费观看| 91亚洲欧美| 欧美猛少妇色xxxxx| 超碰成人av| 亲子乱一区二区三区电影| 视频一区在线免费看| 成人黄色在线免费| 亚洲国产中文在线| 精品在线视频一区二区| 欧美日韩一二三四| 午夜探花在线观看| 国产日韩免费| wwwwxxxx日韩| 国产盗摄精品一区二区三区在线 | 99视频精品在线| 97超碰在线资源| 国产精品久久久久影院亚瑟| 男女性高潮免费网站| 亚洲电影第三页| 真实新婚偷拍xxxxx| 欧美一区三区二区| 日本私人网站在线观看| 色婷婷综合成人av| 美女网站视频在线| 国产精品久久久久久久7电影| 久久免费精品| 蜜桃传媒视频第一区入口在线看| 91偷拍一区二区三区精品| 国产av熟女一区二区三区 | 一女二男3p波多野结衣| 国产成+人+日韩+欧美+亚洲| 免费看污片网站| ...xxx性欧美| 欧美特黄aaaaaa| 777xxx欧美| 你懂的视频在线观看| 九九热精品视频| 日本一道高清亚洲日美韩| 国产日韩欧美二区| 天天综合一区| 国产极品美女高潮无套久久久| 精彩视频一区二区| 亚洲一级中文字幕| 亚洲va欧美va天堂v国产综合| 中文字幕日本人妻久久久免费| 精品国产免费一区二区三区香蕉 | 亚洲精品一区二区三区在线| 日韩精品最新在线观看| 在线亚洲观看| 日批视频免费看| 国产精品欧美精品| 久久久久女人精品毛片九一| 精品国产亚洲在线| 中文av资源在线| 成人免费福利在线| 欧美军人男男激情gay| 欧美精品久久久久久久免费| 国产乱人伦偷精品视频不卡 | 一区二区三区四区不卡在线 | 蜜臀av国产精品久久久久| 亚洲中文字幕一区| 亚洲国产sm捆绑调教视频| 国产婷婷一区二区三区久久| 中文字幕亚洲综合久久筱田步美| 天堂在线中文网官网| 懂色中文一区二区三区在线视频| 午夜国产一区二区| 中文字幕欧美人妻精品一区| www精品美女久久久tv| 日韩av电影网| 精品国产污污免费网站入口| 污污片在线免费视频| 亚洲一区二区久久久久久| 国产韩日影视精品| av亚洲天堂网| 国产精品欧美综合在线| 中文字幕久久久久| 中文字幕亚洲欧美日韩高清| 国模一区二区| 日韩女优中文字幕| 日韩福利视频网| 91精品国自产在线| 欧美性色综合网| 成人在线视频成人| 国产精品爽爽ⅴa在线观看| 欧美日韩精品在线一区| 久久人人爽av| 国产精品久久久久久妇女6080| 伊人网视频在线| 中文字幕在线亚洲| 人人精品久久| 激情视频小说图片| 成人精品国产一区二区4080| 日韩成人高清视频| 日韩av一区二区在线| 精品91久久| 日韩精品无码一区二区三区| 久久成人久久爱| 老湿机69福利| 精品剧情在线观看| 激情aⅴ欧美一区二区欲海潮| 免费国产在线精品一区二区三区| 亚洲欧美日韩国产一区二区| 久久丫精品忘忧草西安产品| 欧美日韩精品一区二区| 最新黄网在线观看| 国产在线精品一区二区三区| 另类av一区二区| eeuss中文字幕| 日韩美女视频一区二区在线观看| 欧美78videosex性欧美| 精品国产_亚洲人成在线| 久久最新视频| 91日韩中文字幕| 亚洲精品wwwww| 69堂精品视频在线播放| 午夜啪啪福利视频| 99九九99九九九视频精品| 97人妻一区二区精品视频| 日韩最新在线视频| 福利在线一区| 黑森林精品导航| 一区二区三区欧美久久| 色视频在线观看福利| 国产精品亚洲网站| 激情一区二区| 欧美成人另类视频| 欧美成人午夜电影| 秋霞国产精品| 300部国产真实乱| 日本一区二区免费在线观看视频| 精品国产黄色片| 国产极品jizzhd欧美| 亚洲性视频h| 美女av免费看|