動態代理
即,動態代理是利用java反射技術,在執行時建立一個實現某些給定介面的新類。
栗子
先定義介面
public interface people {
public String work();
}
實現該介面
public class Teacher implements people{
@Override
public String work() {
System.out.println("教書育人");
return "教書";
}
}
編寫代理類
import com.sun.xml.internal.ws.api.pipe.FiberContextSwitchInterceptor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class WorkHandler implements InvocationHandler {
// 代理類的物件
private Object obj;
public WorkHandler(){
}
// 在呼叫這個方法的時候,會被排程到invoke方法,並將引數傳入
public WorkHandler(Object obj){
this.obj = obj;
}
// 在呼叫給類的方法的時候,會被排程到invoke方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 真實物件執行之前新增操作
// 呼叫obj類的method方法,並且引數為args
Object invoke = method.invoke(obj, args);
// 真實物件執行後新增操作
return invoke;// 返回執行的結果
}
}
最後執行
import java.io.FileInputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class Main {
public static void main(String[] args){
// 要代理的物件
people people = new Teacher(); // 建立要代理的真實物件
// 進行註冊
InvocationHandler handler = new WorkHandler(people);
// 進行建立代理物件
// 定義一個代理物件
people proxy;
// 呼叫Proxy.newProxyInstance方法
// 需要傳入真實物件實現的介面,為下一步呼叫該方法做準備
// 將handler關聯到invocationHandler物件,用於排程到invoke方法
// 由於返回的物件為object型別,需要進行強制型別轉換,保留people介面定義的方法
// 最後一個引數要對物件進行關聯,最後批量生產出物件
proxy = (people) Proxy.newProxyInstance(handler.getClass().getClassLoader(), people.getClass().getInterfaces(), handler);
System.out.println(proxy.work());
}
}
第一個引數
第一個引數是執行時,建立的代理物件。
反射+IO操作讀取class檔案
import java.io.FileInputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Main {
// 需要使用static讓其載入進入記憶體
static class myClassLoader extends ClassLoader{
private String classPath; // 獲取當前類的在磁碟中儲存的地址
// 通過建構函式將地址注入
public myClassLoader(String classPath){
this.classPath = classPath;
}
// 將檔案內容載入進入記憶體
private byte[] loadByte(String name) throws Exception{
// 獲取一個輸入流,
FileInputStream fis = new FileInputStream(classPath + "/" + name + ".class");
// 獲取長度
int len = fis.available();
// 定義byte陣列
byte[] data = new byte[len];
// 載入進入記憶體
fis.read(data);
// 關閉流
fis.close();
return data;
}
// 重寫findClass方法,讓載入的時候呼叫findClass方法
protected Class<?> findClass(String name) throws ClassNotFoundException{
try{
// 讀取檔案到陣列中
byte[] data = loadByte(name);
// 將位元組碼載入進入記憶體當中
return defineClass(name, data, 0, data.length);
}catch(Exception e){
e.printStackTrace();
}
return null;
}
}
public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, ClassNotFoundException {
// 先初始化該類
myClassLoader classLoader = new myClassLoader("/home/ming");
// 此時會呼叫findClass載入Test.class載入進入記憶體當中
Class clazz = classLoader.loadClass("com.ming.Test");
// 例項化該類物件
Object obj = clazz.newInstance();
// 獲取clazz該類方法中名稱為hello,引數為空的方法。
Method helloMethod = clazz.getDeclaredMethod("helloWorld", null);
// 呼叫該方法
// 呼叫obj類中的helloMethod,引數為空的方法。
helloMethod.invoke(obj, null);
}
}