目錄
1.什么是JDK動(dòng)態(tài)代理
2.簡(jiǎn)單案例
3.徹底搞懂JDK動(dòng)態(tài)代理儡嘶,自己動(dòng)手實(shí)現(xiàn)JDK動(dòng)態(tài)代理蹦狂。
4.項(xiàng)目源碼
1.什么是JDK動(dòng)態(tài)代理
JDK動(dòng)態(tài)代理是設(shè)計(jì)模式中代理模式的一種實(shí)現(xiàn)方式,在java的運(yùn)行過(guò)程中窜骄,動(dòng)態(tài)的生成代理類(lèi)邻遏,其只能代理接口准验。
2.簡(jiǎn)單案例
本案例說(shuō)明
(1)創(chuàng)建一個(gè)抽象類(lèi),Person接口糊饱,使其擁有一個(gè)沒(méi)有返回值的doSomething方法另锋。
/**
* 抽象類(lèi)人
*/
public interface Person {
void doSomething();
}
(2)創(chuàng)建一個(gè)名為Bob的Person接口的實(shí)現(xiàn)類(lèi)夭坪,使其實(shí)現(xiàn)doSomething方法唉铜。
/**
* 創(chuàng)建一個(gè)名為Bob的人的實(shí)現(xiàn)類(lèi)
*/
public class Bob implements Person {
public void doSomething() {
System.out.println("Bob doing something!");
}
}
(3)創(chuàng)建JDK動(dòng)態(tài)代理類(lèi)竞惋,使其實(shí)現(xiàn)InvocationHandler接口。擁有一個(gè)名為target的變量拆宛,并創(chuàng)建getTarget獲取代理對(duì)象方法浑厚。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* JDK動(dòng)態(tài)代理
* 需實(shí)現(xiàn)InvocationHandler接口
*/
public class JDKDynamicProxy implements InvocationHandler {
// 被代理的對(duì)象
Person target;
// JDKDynamicProxy構(gòu)造函數(shù)
public JDKDynamicProxy(Person person) {
this.target = person;
}
// 獲取代理對(duì)象
public Person getTarget() {
return (Person) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
// 動(dòng)態(tài)代理invoke方法
public Person invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 被代理方法前執(zhí)行
System.out.println("JDKDynamicProxy do something before!");
// 執(zhí)行被代理的方法
Person result = (Person) method.invoke(target, args);
// 被代理方法后執(zhí)行
System.out.println("JDKDynamicProxy do something after!");
return result;
}
}
(4)創(chuàng)建JDK動(dòng)態(tài)代理測(cè)試類(lèi)JDKDynamicTest。
/**
* JDK動(dòng)態(tài)代理測(cè)試
*/
public class JDKDynamicTest {
public static void main(String[] args) {
System.out.println("不使用代理類(lèi),調(diào)用doSomething方法炎滞。");
// 不使用代理類(lèi)
Person person = new Bob();
// 調(diào)用doSomething方法
person.doSomething();
System.out.println("-------------------------------------- 分割線 --------------------------------------");
System.out.println("使用代理類(lèi),調(diào)用doSomething方法册赛。");
// 獲取代理類(lèi)
Person proxyPerson = new JDKDynamicProxy(new Bob()).getTarget();
// 調(diào)用doSomething方法
proxyPerson.doSomething();
}
}
運(yùn)行結(jié)果如下圖所示:
3.徹底搞懂JDK動(dòng)態(tài)代理,自己動(dòng)手實(shí)現(xiàn)JDK動(dòng)態(tài)代理票堵。
想要自己實(shí)現(xiàn)JDK動(dòng)態(tài)代理悴势,首先我們先梳理下原理:
1.拿到被代理對(duì)象的引用瞳浦,然后獲取其接口叫潦。
2.JDK代理重新生成一個(gè)類(lèi),同時(shí)實(shí)現(xiàn)我們給的代理所實(shí)現(xiàn)的接口矗蕊。
3.同時(shí)拿到代理對(duì)象的引用傻咖。
4.動(dòng)態(tài)生成class文件字節(jié)碼卿操。
5.編譯源代碼害淤,并生成. class文件窥摄。
6.將class文件動(dòng)態(tài)加載到JVM础淤。
7.返回被代理后的代理對(duì)象鸽凶。
好了原理梳理完了,下面就開(kāi)始自己動(dòng)手實(shí)現(xiàn)JDK動(dòng)態(tài)代理吧道伟。(ps:可能部分用語(yǔ)不專(zhuān)業(yè)蜜徽,大家理解下工科妹子的表達(dá)能力)
第1步和第2步完全同上拘鞋,這里就省略不寫(xiě)了啊盆色。
(1)創(chuàng)建自定義InvocationHandler
/**
* 自定義InvocationHandler
*/
public interface LzzInvocationHandler {
Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
(2)創(chuàng)建自定義一個(gè)ClassLoader
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
/**
* 自定義一個(gè)ClassLoader
*/
public class LzzClassLoader extends ClassLoader {
private File baseDir;
public LzzClassLoader() {
String basePath = LzzClassLoader.class.getResource("").getPath();
this.baseDir = new java.io.File(basePath);
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
String className = LzzClassLoader.class.getPackage().getName() + "." + name;
if (baseDir != null) {
File classFile = new File(baseDir, name.replaceAll("\\.", "/") + ".class");
if (classFile.exists()) {
FileInputStream in = null;
ByteArrayOutputStream out = null;
try {
in = new FileInputStream(classFile);
out = new ByteArrayOutputStream();
byte[] buff = new byte[1024];
int len;
while ((len = in.read(buff)) != -1) {
out.write(buff, 0, len);
}
return defineClass(className, out.toByteArray(), 0, out.size());
} catch (Exception e) {
e.printStackTrace();
} finally {
if (null != in) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (null != out) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
classFile.delete();
}
}
}
return null;
}
}
(3)創(chuàng)建自定義Proxy類(lèi)
import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
/**
* 自定義Proxy類(lèi)
*/
public class LzzProxy {
// 換行符
private static String ln = "\r\n";
public static Object newProxyInstance(LzzClassLoader classLoader, Class<?>[] interfaces, LzzInvocationHandler h) {
try {
//1.生成源代碼
String proxySrc = generateSrc(interfaces[0]);
//2.保存將生成出來(lái)的源代碼
String filePath = LzzProxy.class.getResource("").getPath();
File f = new File(filePath + "$Proxy0.java");
FileWriter fw = new FileWriter(f);
fw.write(proxySrc);
fw.flush();
fw.close();
//3.編譯源代碼,生成.CLASS文件
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager manager = compiler.getStandardFileManager(null, null, null);
Iterable iterable = manager.getJavaFileObjects(f);
JavaCompiler.CompilationTask task = compiler.getTask(null, manager, null, null, null, iterable);
task.call();
manager.close();
//4.將class文件動(dòng)態(tài)加載到JVM返回被代理后的對(duì)象
Class proxyClass = classLoader.findClass("$Proxy0");
Constructor c = proxyClass.getConstructor(LzzInvocationHandler.class);
f.delete();
return c.newInstance(h);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private static String generateSrc(Class<?> interfaces) {
StringBuffer src = new StringBuffer();
src.append("package lzzly.custom;" + ln);
src.append("import java.lang.reflect.Method;" + ln);
src.append("public class $Proxy0 implements " + interfaces.getName() + "{" + ln);
src.append("LzzInvocationHandler h;" + ln);
src.append("public $Proxy0(LzzInvocationHandler h) {" + ln);
src.append("this.h = h;" + ln);
src.append("}" + ln);
for (Method m : interfaces.getMethods()) {
src.append("public " + m.getReturnType().getName() + " " + m.getName() + "(){" + ln);
src.append("try{" + ln);
src.append("Method m = " + interfaces.getName() + ".class.getMethod(\"" + m.getName() + "\",new Class[]{});" + ln);
src.append("this.h.invoke(this,m,null);" + ln);
src.append("}catch(Throwable e){e.printStackTrace();}" + ln);
src.append("}" + ln);
}
src.append("}");
return src.toString();
}
}
(4)創(chuàng)建CustomDynamicProxy自定義動(dòng)態(tài)代理類(lèi)
import java.lang.reflect.Method;
/**
* 自定義動(dòng)態(tài)代理類(lèi)
* 實(shí)現(xiàn)LzzInvocationHandler接口
*/
public class CustomDynamicProxy implements LzzInvocationHandler {
// 被代理的對(duì)象
Person target;
// JDKDynamicProxy構(gòu)造函數(shù)
public CustomDynamicProxy(Person person) {
this.target = person;
}
// 獲取代理對(duì)象
public Person getTarget() {
return (Person) LzzProxy.newProxyInstance(new LzzClassLoader(), target.getClass().getInterfaces(), this);
}
// 動(dòng)態(tài)代理invoke方法
public Person invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 被代理方法前執(zhí)行
System.out.println("LzzDynamicProxy do something before!");
// 執(zhí)行被代理的方法
Person result = (Person) method.invoke(target, args);
// 被代理方法后執(zhí)行
System.out.println("LzzDynamicProxy do something after!");
return result;
}
}
(5)創(chuàng)建自定義動(dòng)態(tài)代理測(cè)試類(lèi)
/**
* 自定義動(dòng)態(tài)代理測(cè)試
*/
public class CustomDynamicTest {
public static void main(String[] args) {
System.out.println("不使用代理類(lèi),調(diào)用doSomething方法叛薯。");
// 不使用代理類(lèi)
Person person = new Bob();
// 調(diào)用doSomething方法
person.doSomething();
System.out.println("-------------------------------------- 分割線 --------------------------------------");
System.out.println("使用代理類(lèi),調(diào)用doSomething方法组力。");
// 獲取代理類(lèi)
Person proxyPerson = new CustomDynamicProxy(new Bob()).getTarget();
// 調(diào)用doSomething方法
proxyPerson.doSomething();
}
}
運(yùn)行結(jié)果如下圖所示:
項(xiàng)目源碼
碼云-DynamicProxy:https://gitee.com/OrgXxxx/DynamicProxy