1. 程式人生 > >用 Java 實現攔截器 Interceptor 的攔截功能

用 Java 實現攔截器 Interceptor 的攔截功能

 Java 裡的攔截器是動態攔截 action 呼叫的物件。它提供了一種機制可以使開發者可以定義在一個 action 執行的前後執行的程式碼,也可以在一個 action 執行前阻止其執行,同時也提供了一種可以提取 action 中可重用部分的方式。在AOP(Aspect-Oriented Programming)中攔截器用於在某個方法或欄位被訪問之前進行攔截,然後在之前或之後加入某些操作。

  此外,攔截器在流行的開源框架中也很常見,其依賴的技術就是 Java 的動態代理。理解攔截器的核心原理對理解這些開源框架的體系結構至關重要。下面,咱們就以一個簡單的模型的來說明攔截器實現的一般方法。模型主要分為五個模組,分別:

  • 業務元件,被代理和被攔截的物件;
  • 代理處理器,實現了 InvocationHandler 介面的一個物件;
  • 代理物件,Proxy 物件;
  • 攔截器,普通的 JavaBean,在呼叫業務方法之前或者之後會自動攔截並執行自己的一些方法;
  • 客戶端,執行業務處理的入口。

接下來,咱們就用 Java 語言來實現攔截器 Interceptor 的攔截功能:

第 1 步:建立業務元件介面 BusinessFacade

/**
 * @author 維C果糖
 * @create 2017-03-30
 *
 * GitHub:github.com/guobinhit
 *
 * 業務元件介面
 */

public interface
BusinessFacade {
public void doSomething(); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

第 2步:建立業務元件實現類 BusinessClass

/**
 * @author 維C果糖
 * @create 2017-03-30
 *
 * GitHub:github.com/guobinhit
 *
 * 業務元件介面的實現類
 */

public class BusinessClass implements BusinessFacade {
    public void doSomething() {
        System.out.println("在業務元件 BusinessClass 中呼叫方法: doSomething()"
); } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

第 3 步:建立攔截器 InterceptorClass

/**
 * @author 維C果糖
 * @create 2017-03-30
 *
 * GitHub:github.com/guobinhit
 *
 * 攔截器
 */

public class InterceptorClass {
    // 在 action 之前呼叫
    public void before(){
        System.out.println("在攔截器 InterceptorClass 中呼叫方法: before()");
    }

    // 在 action 之後呼叫
    public void after(){
        System.out.println("在攔截器 InterceptorClass 中呼叫方法: after()");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

第 4 步:建立動態代理處理器工具 DynamicProxyHandler

/**
 * @author 維C果糖
 * @create 2017-03-30
 *
 * GitHub:github.com/guobinhit
 *
 * 動態代理處理器工具
 */

public class DynamicProxyHandler implements InvocationHandler {
    // 宣告被代理物件
    private Object business;

    // 建立攔截器
    private InterceptorClass interceptor = new InterceptorClass();

    /**
   * 動態生成一個代理類物件,並繫結被代理類和代理處理器。
   *
   * @param business
   * @return 代理類物件
   */
    public Object bind(Object business) {
        this.business = business;

        /**
         * Proxy.newProxyInstance(引數1, 引數2, 引數3)
         *
         * 引數1, 表示被代理類的 ClassLoader
         * 引數2, 表示被代理的介面
         * 引數3, 表示代理處理器物件
         *
         * 該方法,返回代理例項
         */

        return Proxy.newProxyInstance(business.getClass().getClassLoader(),
                business.getClass().getInterfaces(),
                this);
    }

    /**
   * 代理需要呼叫的方法,並在該方法呼叫前後,先呼叫聯結器的方法。
   *
   * @param proxy 代理類物件
   * @param method 被代理的介面方法
   * @param args 被代理介面方法的引數
   * @return 方法呼叫返回的結果
   * @throws Throwable
   */
   public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
       Object result = null;
       interceptor.before();
       result = method.invoke(business, args);
       interceptor.after();
       return null;
   }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57

第 5 步:建立客戶端 ClientDemo

/**
 * @author 維C果糖
 * @create 2017-03-30
 *
 * GitHub:github.com/guobinhit
 *
 * 客戶端
 */

public class ClientDemo {
    public static void main(String args[]) {
        // 建立動態代理處理工具
        DynamicProxyHandler handler = new DynamicProxyHandler();

        // 建立業務元件物件
        BusinessFacade business = new BusinessClass();

        // 建立業務元件物件,並用動態代理繫結代理類
        BusinessFacade businessProxy = (BusinessFacade) handler.bind(business);

        // 呼叫業務元件中的方法,演示攔截器效果
        businessProxy.doSomething();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

執行上面的專案程式碼,結果如下圖所示:

1

如上圖所示,顯然咱們攔截器的攔截功能實現啦!

通過這篇文章,咱們可能會對攔截器的實現原理有一個更透徹的理解。But,在真正的專案實踐之中,要想實現攔截器的功能,咱們一般採用繼承類HandlerInterceptorAdapter或者抽象類AbstractInterceptor,或者實現HandleInterceptor介面。也就是說,咱們只需要關心如何重寫方法,而不需要關心其內部的實現原理。