理解攔截器
攔截器可以動態地攔截髮送到指定Action的請求,通過攔截器機制,我們可以在Action執行的前後插入某些代碼。通過這種方式,久可以把多個Action中需要重複指定的代碼提取出來,放在攔截器裏面定義,從而提供更好的代碼重用性。攔截器機制是一種非常靈活的軟件服用方式。
攔截器的實現原理
大部分時候,攔截器方法都是用過代理的方式來調用的。下面以JDK動態代理爲例來介紹如何調用攔截器方法。
下面是一個簡單的Dog接口,因爲JDK動態代理只能對實現了接口的實例來生成代理,因此必須提供一個Dog接口,該接口代碼非常簡單。
1、接口代碼
package cn.cdi.intercepter;
public interface Dog {
//info方法聲明
public void info();
//run方法聲明
public void run();
}
2、下面提供接口的實現
package cn.cdi.intercepter;
public class DogImpl implements Dog {
//info方法的實現,僅僅打印一個字符串
public void info() {
System.out.println("我是一條狗");
}
//run方法的實現,僅僅打印一個字符串
public void run() {
System.out.println("我奔跑迅速");
}
}
3、攔截器類
package cn.cdi.intercepter;
public class DogIntercepter {
//第一個攔截器方法
public void method1() {
System.out.println("=====模擬通用方法=====");
}
//第二個攔截器方法
public void method2() {
System.out.println("=====模擬通用方法=====");
}
}
4、假如我們需呀上面的info方法執行前後分別調用攔截器裏的方法,系統應該如何實現呢?關鍵定義一個ProxyHandler類。該類需要實現InvocationHandler接口,該接口是JDK反射體系裏的一個接口,他是一個可以動態調用目標對象的方法。
package cn.cdi.intercepter;
import java.lang.reflect.InvocationHandler;
public class ProxyHandler implements InvocationHandler{
//需被代理的目標對象
private Object target;
//創建攔截器實例
DogIntercepter di = new DogIntercepter();
//執行代理的目標方法時,該invoke方法會被自動調用
public Object invoke(Objectproxy,java.lang.reflect.Method method,Object[] args) throwsException {
Object[] result = null;
//如果被調用方法的方法名爲info
if(method.getName().equals("info")){
//調用攔截器方法1
di.method1();
result =(Object[]) method.invoke(target, args);
//調用攔截器方法2
di.method2();
}else {
result =(Object[]) method.invoke(target, args);
}
return result;
}
//用於設置傳入目標對象的方法
public void setTarget(Object o) {
this.target = o;
}
}
5、還需要提供一個代理工廠,代理工程的主要作用就是更具目標對象生成一個代理對象:
package cn.cdi.intercepter;
import java.lang.reflect.Proxy;
public class MyProxyFactory {
public static Object getProxy(Object object){
//代理的處理類
ProxyHandler handler = newProxyHandler();
//把該Dog實例託付給代理操作
handler.setTarget(object);
//第一個參數是用來創建動態代理的ClassLoader對象
//只要該對象能訪問Dog接口即可
//第二個參數是接口數組,正是代理該接口的數組
//第三個參數是代理包含的處理實例
returnProxy.newProxyInstance(DogImpl.class.getClassLoader(),object.getClass().getInterfaces(), handler);
}
}
代理工程裏有行代碼:
Proxy.newProxyInstance(DogImpl.class.getClassLoader(),object.getClass().getInterfaces(), handler);
Proxy.newProxyInstance()方法根據接口數組動態創建代理類實例,接口數組通過object.getClass().getInterfaces(),方法獲取,創建代理類是JVM在內存中動態創建,該類實現傳入參數裏接口數組中的全部接口。因此,DynamicProxy要求被代理的必須是接口的實現類,否則無法爲其構造相應的動態實例。
從上面的介紹可以看出,代理工程負責根據目標對象和對應的攔截器生成新的代理對象,代理對象裏的方法是目標方法和攔截器方法的組合。正是通過這種方式,實現了在目標方法之前或者之後,自動調用攔截器方法。
6、運行主程序
package cn.cdi.intercepter;
public class TestDog {
public static void main(String[] args) {
//創建一個Dog實例,該實例將被作爲代理的目標對象
Dog targetObject = newDogImpl();
Dog dog = null;
//以目標對象創建代理
Object proxy =MyProxyFactory.getProxy(targetObject);
if(proxy instanceof Dog){
dog = (Dog)proxy;
}
//測試代理的方法
dog.info();
dog.run();
}
}