淘先锋技术网

首页 1 2 3 4 5 6 7

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代理对象要使用)。