jdk動態代理實例
jdk動態代理模式裏面有個攔截器的概念,在jdk中,只要實現了InvocationHandler接口的類就是一個攔截器類
還使用了些反射的相關概念。
攔截器的概念不瞭解沒關係,假如寫了個請求到action,經過攔截器,然後纔會到action。然後繼續有之後的操作。
攔截器就像一個過濾網,一層層的過濾,只要滿足一定條件,才能繼續向後執行。
攔截器的作用:控制目標對象的目標方法的執行。
攔截器的具體操作步驟:
1.引入類:目標類和一些擴展方法相關的類。
2.賦值:調用構造函數給相關對象賦值
3.合併邏輯處理:在invoke方法中把所有的邏輯結合在一起。最終決定目標方法是否被調用。
下面看具體的代碼實例:
目標接口類:
package com.sss.designPattern.proxy.dynamicProxy.jdkDynamicProxy;
/**
* 目標接口:
* 包含目標方法的聲明
*/
public interface TargetInterface {
/**
* 目標方法
*/
void business();
}
目標類:
package com.sss.designPattern.proxy.dynamicProxy.jdkDynamicProxy;
/**
* 被代理的類
* 目標對象類
* 實現目標接口.
* 繼而實現目標方法。
*/
public class TargetObject implements TargetInterface {
/**
* 目標方法(即目標操作)
*/
@Override
public void business() {
System.out.println("business");
}
}
攔截器:
package com.sss.designPattern.proxy.dynamicProxy.jdkDynamicProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* 動態代理-攔截器
*/
public class MyInterceptor implements InvocationHandler {
private Object target;//目標類
public MyInterceptor(Object target) {
this.target = target;
}
/**
* args 目標方法的參數
* method 目標方法
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("aaaaa");//切面方法a();
//。。。
method.invoke(this.target, args);//調用目標類的目標方法
//。。。
System.out.println("bbbbb");//切面方法f();
return null;
}
}
具體通過調用代理對象,來調用目標對象的目標方法的具體測試:
[java] view plain copy
package com.sss.designPattern.proxy.dynamicProxy.jdkDynamicProxy;
import java.lang.reflect.Proxy;
public class MainTest {
public static void main(String[] args) {
//目標對象
TargetObject target = new TargetObject();
//攔截器
MyInterceptor myInterceptor = new MyInterceptor(target);
/*
* Proxy.newProxyInstance參數:
* 1、目標類的類加載器
* 2、目標類的所有的接口
* 3、攔截器
*/
//代理對象,調用系統方法自動生成
TargetInterface proxyObj = (TargetInterface) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), myInterceptor);
proxyObj.business();
}
}
看完代碼實例,要對這個動態代理進一步理解,要考慮到以下的問題。
1、代理對象是由誰產生的?
JVM,不像上次的靜態代理,我們自己得new個代理對象出來。
2、代理對象實現了什麼接口?
實現的接口是目標對象實現的接口。
同靜態代理中代理對象實現的接口。那個繼承關係圖還是相同的。
代理對象和目標對象都實現一個共同的接口。就是這個接口。
所以Proxy.newProxyInstance()方法返回的類型就是這個接口類型。
3、代理對象的方法體是什麼?
代理對象的方法體中的內容就是攔截器中invoke方法中的內容。所有代理對象的處理邏輯,控制是否執行目標對象的目標方法。都是在這個方法裏面處理的。
4、攔截器中的invoke方法中的method參數是在什麼時候賦值的?
在客戶端,代理對象調用目標方法的時候,此實例中爲:proxyObj.business();實際上進入的是攔截器中的invoke方法,這個時候
,攔截器中的invoke方法中的method參數會被賦值。
最後,爲啥這個方式叫做jdk動態代理呢?
因爲這個動態代理對象是用jdk的相關代碼生成的,所以這個叫jdk動態代理。
後面的cglib動態代理,就是因爲要用到cglib的jar包,所以才叫cglib動態代理。
瞭解了一個,那麼另一個也就差不多啦。就繼續往下看吧。
爲什麼要使用這個cglib來實現這個動態代理呢?因爲spring框架要用。
具體的代碼實現如下:
目標對象類:
package com.sss.designPattern.proxy.dynamicProxy.cglbDynamicProxy;
/**
* 被代理的類
* 目標對象類
*/
public class TargetObject {
/**
* 目標方法(即目標操作)
*/
public void business() {
System.out.println("business");
}
}
攔截器類:
package com.sss.designPattern.proxy.dynamicProxy.cglbDynamicProxy;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* 動態代理-攔截器
*/
public class MyInterceptor implements MethodInterceptor {
private Object target;//目標類
public MyInterceptor(Object target) {
this.target = target;
}
/**
* 返回代理對象
* 具體實現,暫時先不追究。
*/
public Object createProxy() {
Enhancer enhancer = new Enhancer();
enhancer.setCallback(this);//回調函數 攔截器
//設置代理對象的父類,可以看到代理對象是目標對象的子類。所以這個接口類就可以省略了。
enhancer.setSuperclass(this.target.getClass());
return enhancer.create();
}
/**
* args 目標方法的參數
* method 目標方法
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("aaaaa");//切面方法a();
//。。。
method.invoke(this.target, objects);//調用目標類的目標方法
//。。。
System.out.println("bbbbb");//切面方法f();
return null;
}
}
測試類:
[java] view plain copy
package com.sss.designPattern.proxy.dynamicProxy.cglbDynamicProxy;
public class MainTest {
public static void main(String[] args) {
//目標對象
TargetObject target = new TargetObject();
//攔截器
MyInterceptor myInterceptor = new MyInterceptor(target);
//代理對象,調用cglib系統方法自動生成
//注意:代理類是目標類的子類。
TargetObject proxyObj = (TargetObject) myInterceptor.createProxy();
proxyObj.business();
}
}
區別:
首先從文件數上來說,cglib比jdk實現的少了個接口類。因爲cglib返回的代理對象是目標對象的子類。而jdk產生的代理對象和目標對象都實現了一個公共接口。
動態代理分爲兩種:
-
jdk的動態代理
- 代理對象和目標對象實現了共同的接口
- 攔截器必須實現InvocationHanlder接口
-
cglib的動態代理
- 代理對象是目標對象的子類
- 攔截器必須實現MethodInterceptor接口
- hibernate中session.load採用的是cglib實現的