proxy中传入接口,通过接口重构源码(字符串拼接成)String src,再将该src写入磁盘保存为.Java格式,再通过编译器将他编译成.class格式,再将.class格式的文件用字节流写出到Byte[]数组中,再将该数组放置到Jvm中进行执行生成可以在内存中运行的class文件,再通过反射将内存中的class文件的对象创建出来,该代理对象去执行方法。
创建出一个媒婆类实现我们自己实现的InvocationHandle接口;
InvocationHandle是个什么东西呢?他里面有一个方法 invoke(?,?,?)方法,参数1:是后面创建出来的代理类
媒婆类实现了invocationHandle接口,所以媒婆也得实现invocationHandle接口里的invoke()方法。创建出meipo对象,并去调用getInstance()方法,参数传入一个new Girl (),从而去调用静态方法newProxyInstance();
public Object getInstance(Object target) throws Exception{
this.target = target;
Class<?> clazz = target.getClass();
return GPProxy.newProxyInstance(new GPClassLoader(),clazz.getInterfaces(),this);
}
其中:Girl类型
GPClassLoader:这是我们自定义的类加载器,主要作用是将.class文件转化为字节流文件,再将该字节流文件加载到Jvm中,形成一个在内存中的.class
那么newProxyInstance()方法又是做什么的呢?他是根据传入的interface接口,通过generateSrc()方法自动生成一个.Java文件。
String src = generateSrc(interfaces);
//定义了.java文件存放的位置
String filePath = GPProxy.class.getResource("").getPath();
File f = new File(filePath + "$Proxy0.java");
FileWriter fw = new FileWriter(f);
fw.write(src);
fw.flush();
fw.close();
其中generateSrc方法是这样的:它通过拼接字符串和我们传入的Interface接口形成一个.Java模板,其中最关键的一步:m即是接口person中的 findLove(); 然后通过meipo类中的该句代码,通过反射使用了girl对象的findLove方法,meipo中还使用了before()和after()对Girl的原始对象进行了包装,从而达到代理对象丰富原始对象Method的目的。【这块简述代理对象里集成了invocationHandle的子类的目的就是使得代理对象可以通过invocationHandle的子类调用其invoke方法】
method.invoke(this.target,args)
this.h.invoke(this,m,new Object[]{});
可以看出他是调用了和h即meipo对象的invoke方法,meipo的invoke方法可以看出
private static String generateSrc(Class<?>[] interfaces) {
StringBuffer sb = new StringBuffer();
sb.append("package com.renxu.proxy.dProxy;\r\n");
sb.append("import com.renxu.proxy.Person;\r\n");
sb.append("import java.lang.reflect.*;\r\n");
sb.append("public class $Proxy0 implements " + interfaces[0].getName() + "{\r\n");
sb.append("GPInvocationHandler h;\r\n");
sb.append("public $Proxy0(GPInvocationHandler h) { \r\n");
sb.append("this.h = h;");
sb.append("}\r\n");
Method[] var2 = interfaces[0].getMethods();
int var3 = var2.length;
for(int var4 = 0; var4 < var3; ++var4) {
Method m = var2[var4];
Class<?>[] params = m.getParameterTypes();
StringBuffer paramNames = new StringBuffer();
StringBuffer paramValues = new StringBuffer();
StringBuffer paramClasses = new StringBuffer();
for(int i = 0; i < params.length; ++i) {
Class clazz = params[i];
String type = clazz.getName();
String paramName = toLowerFirstCase(clazz.getSimpleName());
paramNames.append(type + " " + paramName);
paramValues.append(paramName);
paramClasses.append(clazz.getName() + ".class");
if (i > 0 && i < params.length - 1) {
paramNames.append(",");
paramClasses.append(",");
paramValues.append(",");
}
}
String var10001 = m.getReturnType().getName();
sb.append("public " + var10001 + " " + m.getName() + "(" + paramNames.toString() + ") {\r\n");
sb.append("try{\r\n");
var10001 = interfaces[0].getName();
sb.append("Method m = " + var10001 + ".class.getMethod(\"" + m.getName() + "\",new Class[]{" + paramClasses.toString() + "});\r\n");
sb.append("this.h.invoke(this,m,new Object[]{});\r\n");
sb.append("}catch(Error _ex) { }");
sb.append("catch(Throwable e){\r\n");
sb.append("throw new UndeclaredThrowableException(e);\r\n");
sb.append("}");
sb.append(getReturnEmptyCode(m.getReturnType()));
sb.append("}");
}
sb.append("}\r\n");
return sb.toString();
}
再将该Java文件进行编译生成.class文件
//将.java文件编译成.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();
转化成字节流文件,再加载到jvm中
Class<?> proxyClass = classLoader.findClass("$Proxy0");
再通过反射,建立代理对象
//返回新的代理对象
Constructor c = proxyClass.getConstructor(GPInvocationHandler.class);
f.delete();
return c.newInstance(h);
Proxy类总览
附内存中的class文件:
代理后的执行结果:
总结:invocationHandle的目的就是让代理类集成它,从而使代理类调用它的invoke()方法。
Proxy的作用是用来创建代理对象,通过传入的接口生成.java-->.class-->Byte[]流-->存在于内存中的class-->拿到其构造方法对象,传入h(为什么要传入h?1:底下的字符串拼接需要.2代理对象要使用)。