被代理的類
package com.example.demo.jdkproxytest;
/**
* Created by PengRong on 2018/12/25.
* 創(chuàng)建Person 接口 用于定義 委托類和代理類之間的約束行為
*/
public interface Person {
/**
* @param name 人名
* @param dst 工作目的地
*/
void goWorking(String name, String dst);
/**
* 獲取名稱
*
* @return
*/
String getName();
/**
* 設(shè)置名稱
*
* @param name
*/
void setName(String name);
}
接口實現(xiàn)類崎脉, 被代理類
package com.example.demo.jdkproxytest;
/**
* Created by PengRong on 2018/12/25.
* 動態(tài)代理委托類實現(xiàn)蹦漠, 實現(xiàn)接口 Person典唇。 被動態(tài)生成的代理類代理
*/
public class SoftwareEngineer implements Person {
private String name;
public SoftwareEngineer() {
}
public SoftwareEngineer(String name) {
this.name = name;
}
@Override
public void goWorking(String name, String dst) {
System.out.println("name =" + name + " 犹褒, 去 " + dst + " 工作");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
InvocationHandler
package com.example.demo.jdkproxytest;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Arrays;
/**
* Created by PengRong on 2018/12/25.
* PersonInvocationHandler 類 實現(xiàn)InvocationHandler接口,這個類中持有一個被代理對象(委托類)的實例target。該類別JDK Proxy類回調(diào)
* InvocationHandler 接口中有一個invoke方法逮壁,當一個代理實例的方法被調(diào)用時凌盯,代理方法將被編碼并分發(fā)到 InvocationHandler接口的invoke方法執(zhí)行。
*/
public class PersonInvocationHandler<T> implements InvocationHandler {
/**
* 被代理對象引用掐隐,invoke 方法里面method 需要使用這個 被代理對象
*/
T target;
public PersonInvocationHandler(T target) {
this.target = target;
}
/**
* 在
*
* @param proxy 代表動態(tài)生成的 動態(tài)代理 對象實例
* @param method 代表被調(diào)用委托類的接口方法狗热,和生成的代理類實例調(diào)用的接口方法是一致的,它對應(yīng)的Method 實例
* @param args 代表調(diào)用接口方法對應(yīng)的Object參數(shù)數(shù)組虑省,如果接口是無參匿刮,則為null; 對于原始數(shù)據(jù)類型返回的他的包裝類型探颈。
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { /**
* 在轉(zhuǎn)調(diào)具體目標對象之前熟丸,可以執(zhí)行一些功能處理
*/
System.out.println("被動態(tài)代理類回調(diào)執(zhí)行, 代理類 proxyClass =" + proxy.getClass() + " 方法名: " + method.getName() + "方法. 方法返回類型:" + method.getReturnType()
+ " 接口方法入?yún)?shù)組: " + (args == null ? "null" : Arrays.toString(args))); /**
* 代理過程中插入監(jiān)測方法,計算該方法耗時
*/
MonitorUtil.start();
Thread.sleep(1); /** 調(diào)用唄代理對象的真實方法,*/
Object result = method.invoke(target, args);
MonitorUtil.finish(method.getName());
return result;
}
}
MonitorUtil
package com.example.demo.jdkproxytest;
/**
* Created by PengRong on 2018/12/25.
* 方法用時監(jiān)控類
*/
public class MonitorUtil {
private static ThreadLocal<Long> tl = new ThreadLocal<>();
public static void start() {
tl.set(System.currentTimeMillis());
}
/**
* 結(jié)束時打印耗時
*
* @param methodName 方法名
*/
public static void finish(String methodName) {
long finishTime = System.currentTimeMillis();
System.out.println(methodName + "方法執(zhí)行耗時" + (finishTime - tl.get()) + "ms");
}
}
測試類
package com.example.demo.jdkproxytest;
import sun.misc.ProxyGenerator;
import java.io.FileOutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Properties;
/**
* 動態(tài)代理類測試
* Created by PengRong on 2018/12/25.
*/
public class JdkDynamicProxyTest {
public static void main(String[] args) throws Exception {
// 打開保存JDK動態(tài)代理生成的類文件
saveGeneratedJdkProxyFiles();
/**
* 第一種方法: 通過 Proxy.newProxyInstance 方法 獲取代理對象
*/
System.out.println("-------------------第一種創(chuàng)建代理類方法--------------");
//創(chuàng)建一個實例對象伪节,這個對象是被代理的對象光羞,委托類
Person person = new SoftwareEngineer("Vincent");
//創(chuàng)建一個與代理類相關(guān)聯(lián)的InvocationHandler,每一個代理類都有一個關(guān)聯(lián)的 InvocationHandler,并將代理類引用傳遞進去
InvocationHandler Handler = new PersonInvocationHandler<>(person);
//創(chuàng)建一個 代理對象 personProxy 來代理 person怀大,創(chuàng)建的代理對象的每個執(zhí)行方法都會被替換執(zhí)行Invocation接口中的invoke方法
Person personProxy = (Person) Proxy.newProxyInstance(Person.class.getClassLoader(), new Class<?>[]{Person.class}, Handler);
/** 代理類信息 */
System.out.println("package = " + personProxy.getClass().getPackage() + " SimpleName = " + personProxy.getClass().getSimpleName() + " name =" + personProxy.getClass().getName() + " CanonicalName = " + "" + personProxy.getClass().getCanonicalName() + " 實現(xiàn)的接口 Interfaces = " + Arrays.toString(personProxy.getClass().getInterfaces()) + " superClass = " + personProxy.getClass().getSuperclass() + " methods =" + Arrays.toString(personProxy.getClass().getMethods())); // 通過 代理類 執(zhí)行 委托類的代碼邏輯
personProxy.goWorking(personProxy.getName(), "深圳");
System.out.println("-------------------第二種創(chuàng)建代理類方法--------------");
/**
* 動態(tài)代理對象步驟
* 1纱兑、 創(chuàng)建一個與代理對象相關(guān)聯(lián)的 InvocationHandler,以及真實的委托類實例
* 2化借、Proxy類的getProxyClass靜態(tài)方法生成一個動態(tài)代理類stuProxyClass潜慎,該類繼承Proxy類,實現(xiàn) Person.java接口;JDK動態(tài)代理的特點是代理類必須繼承Proxy類
* 3勘纯、通過代理類 proxyClass 獲得他的帶InvocationHandler 接口的構(gòu)造函數(shù) ProxyConstructor
* 4局服、通過 構(gòu)造函數(shù)實例 ProxyConstructor 實例化一個代理對象,并將 InvocationHandler 接口實例傳遞給代理類驳遵。
*/
// // 1淫奔、創(chuàng)建 InvocationHandler 實例并設(shè)置代理的目標類對象
// Person persontwo = new SoftwareEngineer("Vincent");
// InvocationHandler Handlertwo = new PersonInvocationHandler<>(persontwo);
//
// // 2 創(chuàng)建代理類,是一個字節(jié)碼文件, 把 proxyClass 保存起來就能看到 他繼承Proxy 類,實現(xiàn)Person接口
// Class<?> proxyClass = Proxy.getProxyClass(Person.class.getClassLoader(), new Class<?>[]{Person.class});
//
// /** 代理類信息 */
// System.out.println("package = " + proxyClass.getPackage() + " SimpleName = " + proxyClass.getSimpleName() + " name =" + proxyClass.getName() + " CanonicalName = " + "" + proxyClass.getCanonicalName() + " 實現(xiàn)的接口 Interfaces = " + Arrays.toString(proxyClass.getInterfaces()) + " superClass = " + proxyClass.getSuperclass() + " methods =" + Arrays.toString(proxyClass.getMethods())); // 3堤结、 通過 proxyClass 獲得 一個帶有InvocationHandler參數(shù)的構(gòu)造器constructor
// Constructor<?> ProxyConstructor = proxyClass.getConstructor(InvocationHandler.class);
//
// // 4唆迁、通過構(gòu)造器創(chuàng)建一個 動態(tài)代理類 實例
// Person stuProxy = (Person) ProxyConstructor.newInstance(Handlertwo);
//
// /** 檢測生成的類是否是代理類 */
// System.out.println("stuProxy isProxy " + Proxy.isProxyClass(stuProxy.getClass()));
//
// /** 獲取 代理類關(guān)聯(lián)的 InvocationHandler 是哪個*/
// InvocationHandler handlerObject = Proxy.getInvocationHandler(stuProxy);
// System.out.println(handlerObject.getClass().getName());
// stuProxy.goWorking(stuProxy.getName(), "廣州");
//
// // 保存代理類
// String pathdir = "/Users/benjamin/IntelliJIdeaProjects/springboot-mydemo/demo/jdkdynamicclasses";
// saveClass("$PersonProxy0", proxyClass.getInterfaces(), pathdir);
}
/**
* 生成代理類 class 并保持到文件中
*
* @param className 生成的代理類名稱
* @param interfaces 代理類需要實現(xiàn)的接口
* @param pathdir 代理類保存的目錄路徑,以目錄分隔符結(jié)尾
*/
public static void saveClass(String className, Class<?>[] interfaces, String pathdir) { /**
* 第一個參數(shù)是 代理類 名 。
* 第二個參數(shù)是 代理類需要實現(xiàn)的接口
*/
byte[] classFile = ProxyGenerator.generateProxyClass(className, interfaces);
/**
* 如果目錄不存在就新建所有子目錄
*/
Path path1 = Paths.get(pathdir);
if (!path1.toFile().exists()) {
path1.toFile().mkdirs();
}
String path = pathdir + className + ".class";
try (FileOutputStream fos = new FileOutputStream(path)) {
fos.write(classFile);
fos.flush();
System.out.println("代理類class文件寫入成功");
} catch (Exception e) {
System.out.println("寫文件錯誤");
}
}
/**
* 設(shè)置保存Java動態(tài)代理生成的類文件竞穷。
*
* @throws Exception
*/
public static void saveGeneratedJdkProxyFiles() throws Exception {
Field field = System.class.getDeclaredField("props");
field.setAccessible(true);
Properties props = (Properties) field.get(null);
props.put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
}
}
生成的代理類的字節(jié)碼
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.sun.proxy;
import com.example.demo.jdkproxytest.Person;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class $Proxy0 extends Proxy implements Person {
private static Method m1;
private static Method m4;
private static Method m3;
private static Method m2;
private static Method m5;
private static Method m0;
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final void setName(String var1) throws {
try {
super.h.invoke(this, m4, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final String getName() throws {
try {
return (String)super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void goWorking(String var1, String var2) throws {
try {
super.h.invoke(this, m5, new Object[]{var1, var2});
} catch (RuntimeException | Error var4) {
throw var4;
} catch (Throwable var5) {
throw new UndeclaredThrowableException(var5);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m4 = Class.forName("com.example.demo.jdkproxytest.Person").getMethod("setName", Class.forName("java.lang.String"));
m3 = Class.forName("com.example.demo.jdkproxytest.Person").getMethod("getName");
m2 = Class.forName("java.lang.Object").getMethod("toString");
m5 = Class.forName("com.example.demo.jdkproxytest.Person").getMethod("goWorking", Class.forName("java.lang.String"), Class.forName("java.lang.String"));
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}