簡述
- 前面我們了解了動態(tài)代理以及JDK動態(tài)代理技術,由于動態(tài)代理比較難理解,程序設計者通常會設計一個攔截器接口給開發(fā)人員使用,開發(fā)人員只需要實現(xiàn)該接口并像應用注冊即可。
- SpringMvc中的攔截器就是這樣,實現(xiàn)org.springframework.web.servlet.HandlerInterceptor接口,然后向配置文件中去注冊該實現(xiàn)類。
代碼案例
本案例所有代碼可到動態(tài)代理之攔截器中去下載
【攔截器接口】
//攔截器接口
import java.lang.reflect.Method;
public interface Interceptor {
boolean before(Object proxy, Object target, Method method, Object[] args);
void around(Object proxy, Object target, Method method, Object[] args);
void after(Object proxy, Object target, Method method, Object[] args);
}
【攔截器實現(xiàn)類】
//攔截器實現(xiàn)類
import java.lang.reflect.Method;
public class MyInterceptor implements Interceptor {
@Override
public boolean before(Object proxy, Object target, Method method, Object[] args) {
System.err.println("反射方法前邏輯 --- 判斷用戶是否處于登錄狀態(tài) --- 用戶未登錄,操作攔截");
return false;//不反射被代理對象原有方法,這里true或false根據(jù)開發(fā)人員需求自定義
}
@Override
public void around(Object proxy, Object target, Method method, Object[] args) {
System.err.println("取代了被代理對象的方法 --- 頁面轉(zhuǎn)發(fā)到登錄頁面");
}
@Override
public void after(Object proxy, Object target, Method method, Object[] args) {
System.err.println("反射方法后的邏輯 --- 記錄本次異常操作");
}
}
【動態(tài)代理邏輯】
//動態(tài)代理邏輯
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class InterceptorJdkProxy implements InvocationHandler {
private Object target;//真實對象
private String interceptorClass = null;//攔截器全限定名
public InterceptorJdkProxy(Object target, String interceptorClass) {
this.target = target;
this.interceptorClass = interceptorClass;
}
/**
* 綁定委托對象,并返回一個【代理占位】
* @param target 真實對象
* @param interceptorClass
* @return 代理對象【占位】
*/
public static Object bind(Object target, String interceptorClass){
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
new InterceptorJdkProxy(target, interceptorClass));
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if(interceptorClass == null){
//代表沒有設置攔截器,直接反射原有方法
return method.invoke(target, args);
}
Object result = null;
//通過反射生成攔截器
Interceptor interceptor = (Interceptor) Class.forName(interceptorClass).newInstance();
//調(diào)用前置方法
if(interceptor.before(proxy, target, method, args)){
result = method.invoke(target, args);
}else {
interceptor.around(proxy, target, method, args);
}
//調(diào)用后置方法
interceptor.after(proxy, target, method, args);
return result;
}
}
【測試】
//測試
import com.bpf.chapter2.proxy.jdkProxy.HelloWorld;
import com.bpf.chapter2.proxy.jdkProxy.HelloWorldImpl;
public class TestInterceptor {
public static void main(String[] args) {
//注冊攔截器
HelloWorld proxy1 = (HelloWorld) InterceptorJdkProxy.bind(new HelloWorldImpl(),
"com.bpf.chapter2.proxy.interceptor.MyInterceptor");
//不注冊攔截器
HelloWorld proxy2 = (HelloWorld) InterceptorJdkProxy.bind(new HelloWorldImpl(), null);
proxy1.sayHelloWorld();
/*
結(jié)果
反射方法前邏輯 --- 判斷用戶是否處于登錄狀態(tài) --- 用戶未登錄,操作攔截
取代了被代理對象的方法 --- 頁面轉(zhuǎn)發(fā)到登錄頁面
反射方法后的邏輯 --- 記錄本次異常操作
*/
proxy2.sayHelloWorld();
/*
結(jié)果
hello world!
*/
}
}