用 Java 實現攔截器 Interceptor 的攔截功能
阿新 • • 發佈:2019-01-27
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
執行上面的專案程式碼,結果如下圖所示:
如上圖所示,顯然咱們攔截器的攔截功能實現啦!
通過這篇文章,咱們可能會對攔截器的實現原理有一個更透徹的理解。But,在真正的專案實踐之中,要想實現攔截器的功能,咱們一般採用繼承類HandlerInterceptorAdapter
或者抽象類AbstractInterceptor
,或者實現HandleInterceptor
介面。也就是說,咱們只需要關心如何重寫方法,而不需要關心其內部的實現原理。