今天學習了struts2的攔截器的相關知識。下面是自己自定義的一個攔截器的實現原理。下面爲大家解析一下編寫一個自定義攔截器原理的步驟及代碼。
大部分時候,攔截器方法都是通過代理的方式來調用的,下面以JDK動態代理爲例來介紹如何調用攔截器方法。
第一步:
首先要定義一個簡單的Dog接口,因爲JDK動態代理只能對實現了接口的實例來生成代理,因此必須提供一個Dog接口,該接口代碼非常簡單。在接口中要定義兩個簡單的方法。
public interface Dog {
//狗的信息
public void info();
//狗跑
public void run();
}
第二步:
在以上接口中,並沒有實現其方法,爲了能正常使用Dog實例,必須要提供一個該接口的實現類。實現類的代碼:如下:
public class DogImpl implements Dog{
public void info() {
//info方法實現,僅僅打印一個字符串
System.out.println("他是一隻小獵狗!");
}
public void run() {
// run方法實現,僅僅打印一個字符串
System.out.println("他奔跑迅速!");
}
}
第三步:
下面就來編寫一個攔截Dog實例的攔截器。
系統用於攔截Dog實例的攔截器類如下:
public class DogInterceptor {
//第一個攔截器的方法
public void log(){
System.out.println("*****通用方法一******");
}
//第二個攔截器的方法
public void safe(){
System.out.println("*****通用方法二******");
}
}
通過以上的攔截器,它也是一個普通的java類。假設我們需要上面的info方法執行前後分別調用攔截器裏的方法,系統應該如何來實現呢?關鍵是要編寫ProxyHandler類。該類需要實現InvocationHandler接口,該接口是JDK反射體系裏的一個接口,它可以動態調用目標對象的方法。
ProxyHandler類的代碼如下:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class ProxyHandler implements InvocationHandler{
//需要聲明被代理的目標對象
private Object target;
//創建一個攔截器的實例
DogInterceptor dogInterceptor = new DogInterceptor();
//執行代理目標方法的時候,該invoke被自動調用
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result = null;
//proxy
//method方法
if(method.getName().equals("info")){
dogInterceptor.log();
result = method.invoke(target, args);
dogInterceptor.safe();
}else{
result = method.invoke(target, args);
}
//args方法參數
return result;
}
public Object getTarget() {
return target;
}
public void setTarget(Object target) {
this.target = target;
}
}
第四步:
通過ProxyHandler的幫助,系統實現了在執行info方法之前,調用攔截器的method方法:在指定info方法之後,調用攔截器的run方法。
只因爲上面類與被攔截對象沒有絲毫耦合,從而提供了更好解耦,以及更好的可擴展性。但上面的類與兩個地方耦合了:
(1) 與攔截器類耦合:上面類固定使用DogIntercepter攔截器。
(2) 與被攔截器的方法耦合:上面類指定攔截名爲info的方法。
系統還需要提供一個代理工廠,代理工廠的主要作用就是根據目標對象生成一個代理對象。
下面就是一個代理工廠類的代碼:
package cn.csdn.hr.jdk.inter;
import java.lang.reflect.Proxy;
//根據目標對象 產生代理對象
public class MyProxyFactory {
public static Object getProxy(Object target){
//創建代理類的處理類
ProxyHandler proxyHandler = new ProxyHandler();
//傳遞目標對象 到代理對象中
proxyHandler.setTarget(target);
return Proxy.newProxyInstance(DogImpl.class.getClassLoader(),target.getClass().getInterfaces(),proxyHandler);
}
}
第五步:
通過這種方式,實現了在目標方法之前或者之後,自動調用攔截器方法的目的。
下面是測試的方法,代碼如下:
public class DogTest {
public static void main(String[] args){
Dog targetDog = new DogImpl();
Object proxy = MyProxyFactory.getProxy(targetDog);
Dog dog = null;
if(proxy instanceof Dog){
dog = (Dog) proxy;
}
if(dog != null){
dog.info();
dog.run();
}
}
}
第六步:
上面的代碼先是創建了一個Dog實例作爲目標對象,然後以該目標對象,創建該對象的搭理對象——代理對象裏的方法,是攔截器方法和目標對象方法的組合,這就是爲什麼可以在執行目標方法的前後,執行攔截器方法的原因。
上面程序執行後的結果:
*****通用方法一******
他是一隻小獵狗!
*****通用方法二******
他奔跑迅速!