Spring入門系列-動態代理
阿新 • • 發佈:2021-06-27
動態代理
- 動態代理和靜態代理的角色一樣
- 動態代理的代理類是動態生成的,不是我們直接寫好的
- 動態代理可以分為兩大類,基於介面的動態代理,基於類的動態代理
- 基於介面---JDK動態代理[我們在這裡使用]
- 基於類---cglib
- Java位元組碼實現:Javassist
需要了解兩個類 Proxy:代理,invocationHandler:呼叫代理程式
在此之前,我們要思考class和interface的區別和關係:
- 可以例項化class(非abstract)
- 不可以例項化interface
所有的interface型別的變數都是通過向上轉型並指向某個例項的
CharSequence charSequence=new StringBuffer();
有沒有可能不編寫實現類,自動生成介面所指向的例項呢?
答案是可以的,Java標準庫提供了對應的機制:可以在執行期間動態的建立某個interface的例項,什麼叫做動態的建立呢?我們先看一下靜態情況下是怎樣的。
1.編寫介面
package com.dreamcold.aop.demo02;
public interface Hello {
void sayHello();
}
- 編寫具體實現類
package com.dreamcold.aop.demo02; public class HelloWorld implements Hello { public void sayHello(){ System.out.println("Hello World"); } }
3.測試
package com.dreamcold.aop.demo02;
public class Demo01 {
public static void main(String[] args) {
Hello hello=new HelloWorld();
hello.sayHello();
}
}
- 輸出
還有另外一種方式是動態程式碼,過程如下:
- 我們仍然先定義介面Hello
- 但是我們不編寫實現類
- 實現類是通過JDK提供的一個Proxy.newProxyInstance()建立了一個Hello介面物件
- 這種沒有實現類,但是在執行期間建立一個介面物件的方式稱為動態程式碼
- JDK提供的動態建立介面物件的方式,叫做動態代理。
1.先定義介面
package com.dreamcold.aop.demo03;
public interface Hello {
void sayGoodMorning(String name);
}
2.實現動態代理
package com.dreamcold.aop.demo03;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class HelloWorld {
public static void main(String[] args) {
//invocationHandler負責介面的方法呼叫
InvocationHandler handler=new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//列印方法
System.out.println(method);
if(method.getName().equals("sayGoodMorning")){
System.out.println("Good Morning "+args[0]);
}
return null;
}
};
//負責建立interface例項
Hello hello=(Hello) Proxy.newProxyInstance(
Hello.class.getClassLoader(),
new Class[]{Hello.class},
handler
);
hello.sayGoodMorning("dreamcold");
}
}
在執行的時候建立一個interface例項的方法如下:
- 定義一個InvocationHandler例項,它負責實現介面方法的呼叫
- 通過Proxy.newInstance()建立interface實錄,它需要三個引數
- 使用ClassLoader,通常就是介面類的ClassLoader
- 需要實現的介面資料,至少需要傳入一個介面進去
- 用來處理介面方法呼叫的Invocationhandler例項
- 將返回的Object強制轉換為介面
實質:動態代理實際上就是JDK在執行期間建立class位元組碼並載入的過程,它並沒有什麼黑魔法,把上面的靜態實現類:
public class HelloDynamicProxy implements Hello {
InvocationHandler handler;
public HelloDynamicProxy(InvocationHandler handler) {
this.handler = handler;
}
public void morning(String name) {
handler.invoke(
this,
Hello.class.getMethod("morning", String.class),
new Object[] { name });
}
}
其實就是JDK幫助我們自動編寫了一個上述類(不需要原始碼,可以直接生成位元組碼),並不存在直接可以直接例項化介面的黑魔法。
總結
- Java標準庫提供類動態代理的功能,允許在執行期間動態的建立一個介面例項
- 動態代理是通過Proxy建立代理物件,然後將介面代理給InvocationHandler完成的
學習自連結:狂神說