一般来说最常见的动态代理是这么写的:
1,正常版本
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JDKProxy implements InvocationHandler {
private Object target;
public Object getInstance(Object target){
this.target = target;
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("JDProxy execute before...");
Object result = method.invoke(target,args);
System.out.println("JDProxy execute after...");
return result;
}
}
2,改进版本
public class ProxyFactory {
public static Object getProxyInstance(Object target) {
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
/* System.out.println(proxy);
System.out.println(method);
System.out.println(args);*/
System.out.println("日志记录begin");
Object result = method.invoke(target, args);
System.out.println("日志记录end");
return result;
}
});
}
}
首先跟一下Proxy.newProxyInstance
System.out.println(sonProxy.getClass());
class com.sun.proxy.$Proxy0
代理类的class为$Proxy,就是意味着 Proxy.newProxyInstance的功能就是产生一个$Proxy,而$Proxy是什么呢?有一个骚操作
通过反编译工具查看class的源码
byte[] $Proxy0s = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{Person.class});
FileOutputStream fileOutputStream = new FileOutputStream("E://$Proxy123.class");
fileOutputStream.write($Proxy0s);
fileOutputStream.flush();
fileOutputStream.close();
然后把 $Proxy123.class放到idea里面就能看到内容:
public final class $Proxy0 extends Proxy implements Person {
private static Method m1;
private static Method m3;
private static Method m2;
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 findLove() throws {
try {
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 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"));
m3 = Class.forName("com.huffman.pattern.proxy.dynamic_jdk.Person").getMethod("findLove");
m2 = Class.forName("java.lang.Object").getMethod("toString");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
可以看出来 Proxy.newProxyInstance具体做的就是生成一个代理类$Proxy,代理类里面克隆了当前类所有方法,而且调用findxxx()方法时其实是调用在定义InvocationHandler.invoke()定义的方法;
所以我们的手写动态代理的思路为:
1,直接生成$proxy.java
2,把$proxy.java编译成$proxy.class
3,用类加载器把$proxy.class生成class实例
4,把class实例返回代理对象
所以重写Proxy的newProxyInstance用代码实现为:
public static Object newProxyInstance(MyClassLoader classLoader,Class<?>[] interfaces,MyInvocationHandler myInvocationHandler) throws IllegalArgumentException, IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//1.动态生成java文件源码
String src=generateSrc(interfaces);
//2.将java源码生成本地文件
String classPath = MyProxy.class.getResource("").getPath();
File file = new File(classPath + "$Proxy0.java");
FileWriter fileWriter = new FileWriter(file);
fileWriter.write(src);
fileWriter.flush();
fileWriter.close();
//3.动态编译java源码,生成class文件
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager manage = compiler.getStandardFileManager(null,null,null);
Iterable iterable = manage.getJavaFileObjects(file);
JavaCompiler.CompilationTask task = compiler.getTask(null,manage,null,null,null,iterable);
task.call();
manage.close();
//4.加载class文件生成Class实例
Class proxyClass = classLoader.findClass("$Proxy0");
Constructor c = proxyClass.getConstructor(MyInvocationHandler.class);
// file.delete();
//5.根据类型Class生成代理对象
return c.newInstance(myInvocationHandler);
}
自定义类加载器就是把本地生成的$Proxy0.class加载到jvm
public class MyClassLoader extends ClassLoader {
private File classPathFile;
public MyClassLoader(){
String classPath = MyClassLoader.class.getResource("").getPath();
this.classPathFile = new File(classPath);
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
String className = MyClassLoader.class.getPackage().getName() + "." + name;
if(classPathFile != null){
File classFile = new File(classPathFile,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(out != null){
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
return null;
}
}
至此,手动实现动态代理就完成了;