在Java中,動態代理是一種機制,允許在運行時動態地創建代理對象來代替某個實際對象,從而在其前后執行額外的邏輯。
為什么JDK動態代理只能代理接口實現類,原因是JDK動態代理是基于接口實現的。
當你使用Proxy
類創建代理對象時,你需要指定一個接口列表來表示代理對象所應該實現的接口,這些接口就成為代理對象的類型。
具體來說,代理對象的方法調用會被轉發到實現InvocationHandler
接口的類中的invoke()
方法。這個invoke()
方法接受三個參數:代理對象本身、被調用的方法對象和方法的參數數組。invoke()
方法需要返回被代理方法調用的結果。
由于代理對象的類型是由接口列表決定的,因此只有實現了接口的類才能被代理。如果你想代理一個類而不是一個接口,你需要使用其他的代理技術,比如CGLIB。
1、JDK動態代理代碼實例
下面是一個簡單的示例代碼,展示了如何使用JDK動態代理來創建代理對象。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyDemo {
public static void main(String[] args) {
RealObject real = new RealObject();
InvocationHandler handler = new DynamicProxy(real);
// 創建代理對象
MyInterface proxy = (MyInterface) Proxy.newProxyInstance(
MyInterface.class.getClassLoader(),
new Class< ? >[] { MyInterface.class },
handler);
// 調用代理對象的方法
proxy.doSomething();
}
}
interface MyInterface {
void doSomething();
}
class RealObject implements MyInterface {
public void doSomething() {
System.out.println("RealObject doSomething");
}
}
class DynamicProxy implements InvocationHandler {
private Object target;
public DynamicProxy(Object target) {
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("Before method invocation");
Object result = method.invoke(target, args);
System.out.println("After method invocation");
return result;
}
}
在上面的代碼中,RealObject
實現了MyInterface
接口,它是我們要代理的實際對象。DynamicProxy
類實現了InvocationHandler
接口,并在invoke()
方法中添加了額外的邏輯,用于在代理對象方法調用前后執行。
在main()
方法中,我們使用Proxy.newProxyInstance()
方法創建代理對象。我們指定了MyInterface
接口作為代理對象類型,并將DynamicProxy
對象作為代理對象的InvocationHandler
。
最后,我們調用代理對象的doSomething()
方法,并觀察控制臺輸出的結果。
需要注意的是,代理對象的方法調用都會被轉發到DynamicProxy
類的invoke()
方法中進行處理,因此在這個示例中,實際的RealObject
對象的doSomething()
方法的執行是在invoke()
方法中通過反射進行的。
總結一下,JDK動態代理只能代理接口實現類,原因是JDK動態代理是基于接口實現的,代理對象的類型由接口列表決定。如果你想代理一個類而不是一個接口,你需要使用其他的代理技術,比如CGLIB。
2、Cglib 代碼演示
以下是CGLIB代理的示例代碼。
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 CGLIBProxyDemo {
public static void main(String[] args) {
RealObject real = new RealObject();
MethodInterceptor handler = new CGLIBProxy(real);
// 創建代理對象
RealObject proxy = (RealObject) Enhancer.create(
RealObject.class,
handler);
// 調用代理對象的方法
proxy.doSomething();
}
}
class CGLIBProxy implements MethodInterceptor {
private Object target;
public CGLIBProxy(Object target) {
this.target = target;
}
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("Before method invocation");
Object result = proxy.invoke(target, args);
System.out.println("After method invocation");
return result;
}
}
在上面的示例中,我們使用CGLIB的Enhancer
類和MethodInterceptor
接口來創建代理對象。RealObject
類不再需要實現接口,而是直接作為代理對象的類型。在CGLIBProxy
類中,我們實現了MethodInterceptor
接口,并在intercept()
方法中添加了額外的邏輯。
在main()
方法中,我們使用Enhancer.create()
方法創建代理對象。我們指定了RealObject
類作為代理對象類型,并將CGLIBProxy
對象作為代理對象的MethodInterceptor
。最后,我們調用代理對象的doSomething()
方法,并觀察控制臺輸出的結果。
需要注意的是,CGLIB代理使用字節碼技術來生成代理對象,因此它的效率比JDK動態代理要高,但是它也需要額外的庫依賴。
3、兩者優缺點
JDK動態代理和CGLIB代理都有它們自己的優缺點。
JDK動態代理的優點:
- JDK動態代理是Java標準庫的一部分,因此它不需要引入任何外部依賴。
- JDK動態代理只需要實現接口即可生成代理對象,不需要改變原有類的結構。
- 由于JDK動態代理是基于接口實現的,因此它更適合用于代理接口實現類的場景。
JDK動態代理的缺點:
- JDK動態代理只能代理實現了接口的類,無法代理沒有實現接口的類。
- JDK動態代理在生成代理對象時,需要使用反射機制,因此它的效率相對較低。
CGLIB代理的優點:
- CGLIB代理是基于字節碼技術實現的,因此它的效率比JDK動態代理更高。
- CGLIB代理可以代理沒有實現接口的類。
CGLIB代理的缺點:
- CGLIB代理需要引入外部依賴。
- CGLIB代理在生成代理對象時,需要改變原有類的結構,因此它可能會引起一些問題,例如無法代理final類或final方法等問題。
綜上所述,JDK動態代理適用于代理接口實現類的場景,而CGLIB代理適用于代理沒有實現接口的類的場景。如果你需要代理接口實現類,而且不想引入額外的依賴,那么JDK動態代理是一個不錯的選擇;如果你需要代理沒有實現接口的類,那么CGLIB代理可能更適合你的需求。
-
接口
+關注
關注
33文章
8848瀏覽量
152804 -
代理
+關注
關注
1文章
44瀏覽量
11278 -
數組
+關注
關注
1文章
419瀏覽量
26241 -
JDK
+關注
關注
0文章
82瀏覽量
16752
發布評論請先 登錄
相關推薦
javaassit如何實現代對目標類的代理


JDK的安裝、環境配置及使用
java jdk6.0官方下載

java的動態代理機制和作用
java的動態代理
什么是動態ip代理電腦軟件?

評論