責任鏈模式與其在Spring MVC中的應用

責任鏈模式的應用

   現有一開發場景,要求設計一個集團採購物品,不同金額交由不同領導審批的流程

   現有三級領導,金額在5000以下的,由部門領導審批;金額在10000以下的由院校級領導審批;金額在10000以上的,由校級領導審批。雖然使用 if-else 也能實現改功能,但是代碼的可讀性、可擴展性差,使用責任鏈設計模式,是面向對象的思維方式,符合“開閉原則”,具體實現的代碼如下:
責任鏈調用發起者

 public static void main(String[] args) {
        PurchaseRequest purchaseRequest = new PurchaseRequest(1, 5001, 11);

        DepartmentApprover departmentApprover = new DepartmentApprover("部門審批者 張xx");
        CollegeApprover collegeApprover = new CollegeApprover("院系審批者 李xx");
        SchoolMasterApprover schoolMasterApprover = new SchoolMasterApprover("校長審批 王xx");

        //設置責任鏈的下一個處理類(該段設置chain的邏輯,也可以在不同的approver子類中設置,但缺點是不易管理)
        departmentApprover.nextApprover=collegeApprover;
        collegeApprover.nextApprover=schoolMasterApprover;
        //爲實現調用chain中任意一個處理類,都可以得到正確的結果,在這裏構建一個環形鏈表
        schoolMasterApprover.nextApprover=departmentApprover;

        schoolMasterApprover.processRequest(purchaseRequest);//輸出:請求編號:11 當前審批人名:院系審批者 李xx
    }

批准人抽象類

public abstract class Approver {
    Approver nextApprover;//下一個處理者
    String name;

    public Approver(String name) {
        this.name = name;
    }
    //交由子類去完善處理審批的邏輯
    public abstract void processRequest(PurchaseRequest purchaseRequest);
}

部門審批者、院系審批者、校長審批實現類

public class DepartmentApprover extends Approver{

    public DepartmentApprover(String name) {
        super(name);
    }

    @Override
    public void processRequest(PurchaseRequest purchaseRequest) {
        if(purchaseRequest.price<=5000f){
            System.out.println("請求編號:" + purchaseRequest.id + " 當前審批人名:" + this.name);
        }else {
            nextApprover.processRequest(purchaseRequest);
        }
    }
}


public class CollegeApprover extends Approver {
    public CollegeApprover(String name) {
        super(name);
    }

    @Override
    public void processRequest(PurchaseRequest purchaseRequest) {
        if (purchaseRequest.price > 5000f && purchaseRequest.price <= 10000) {
            System.out.println("請求編號:" + purchaseRequest.id + " 當前審批人名:" + this.name);
        } else {
            nextApprover.processRequest(purchaseRequest);
        }
    }
}


public class SchoolMasterApprover extends Approver {
    public SchoolMasterApprover(String name) {
        super(name);
    }

    @Override
    public void processRequest(PurchaseRequest purchaseRequest) {
        if(purchaseRequest.price>10000f){
            System.out.println("請求編號:" + purchaseRequest.id + " 當前審批人名:" + this.name);
        }else {
            nextApprover.processRequest(purchaseRequest);
        }
    }
}

使用責任鏈的注意事項和細節

  • 降低了流程中,調用鏈鏈中某一節點執行邏輯的耦合度,提高了系統的靈活性
  • 當鏈中節點比較多時,系統的性能會受到影響,因此,可以考慮控制最長鏈節點。

設計模式是一種思想,在不同的地方,實現的方式可能不同,但大致的思想都是一致的,都是爲了提高擴展性,可讀性等原因。


責任鏈在 Spring MVC 的 HandlerExecutionChain 中的應用源碼解析

在 Spring MVC 的 DispatcherServlet 類中,有如下的主要代碼邏輯:
  doDispatch方法中,構建了 interceptor 執行鏈,將請求分配給 preHandle 執行,當 preHandle 方法返回爲 false時,會調用到 afterCompletion 執行,最後調用 postHandle 方法。

protected void doDispatch (HttpServletRequest request, HttpServletResponse response) throws Exception {
            HandlerExecutionChain mappedHandler = null;
            mappedHandler = getHandler(processedRequest);
            if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                return;
            }
           //當上面的 applyPreHandle 返回false時,繼續向下執行到
            mappedHandler.applyPostHandle(processedRequest, response, mv);
}


//調用攔截器的 interceptor.preHandle
boolean applyPreHandle (HttpServletRequest request, HttpServletResponse response) {
    HandlerInterceptor[] interceptors = getInterceptors();
    if (!ObjectUtils.isEmpty(interceptors)) {
        for (int i = 0; i < interceptors.length; i++) {
            HandlerInterceptor interceptor = interceptors[i];
            if (!interceptor.preHandle(request, response, this.handler)) {
                triggerAfterCompletion(request, response, null);
                return false;
            }
            this.interceptorIndex = i;*}
    }
    return true;
}
void triggerAfterCompletion (HttpServletRequest request, HttpServletResponse response,Exception ex){
     HandlerInterceptor interceptor = interceptors[i];
     try {
         interceptor.afterCompletion(request, response, this.handler, ex);
     }
 }
        
//調用攔截器的 interceptor.postHandle
void applyPostHandle (HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv){
    HandlerInterceptor interceptor = interceptors[i];
    interceptor.postHandle(request, response, this.handler, mv);
}
  • HandlerExecutionChain 本身不會執行 interceptor 的邏輯,只是將請求分配給 chain 上註冊的 interceptor 執行;
  • HandlerExecutionChain 維護了 HandlerInterceptor 的集合。

監聽器(listener)、過濾器(filter)、攔截器(interceptor)的執行順序參考
SpingMvc的整體執行流程參考

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