jdk提供的动态代理,依赖接口 InvocationHandler ,并且实现其中的Invoke 方法。

底层实现的具体过程

  1. jdk 首先需要获取到被代理类的接口。
  2. jdk 会动态创建一个代理类,并且实现被代理类的即可
  3. 同时,这个新代理类获取到 被代理类的引用,生成java 类文件。 会额外创建一个java文件,后期删除掉即可
  4. 通过编译生成 class 文件。 会额外创建一个 class文件,classLoader 将其加载到jvm中,并且获取到类的定义后,删除即可。
  5. 将class 文件里的类 加载到 jvm 中。实例化代理类对象。
  6. 代理类就可以执行了。

自定义实现简单的动态代理

依照例子,实现自己的简单代理。需要以下几个部分。

一、 几个外围类

  1. 依赖的接口,Person
  1. package com.zxy.st.lv1.jdk;
  2. /**
  3. * @author : wb-zxy450245
  4. * @date : 2019/10/10
  5. */
  6. public interface Person {
  7. void findLove();
  8. }
  1. 被代理的求婚者 小星星
package com.zxy.st.lv1.jdk;

/**
 * @author : wb-zxy450245
 * @date :  2019/10/10
 */
public class Xiaoxingxing implements Person {

    @Override
    public void findLove() {
        System.out.println("我叫小新星,我的择偶标准是:");
        System.out.println("高富帅");
        System.out.println("180高,体重70公斤左右");
        System.out.println("有车有房");
    }
}
  1. 调用代理的main 方法
package com.zxy.st.lv1.jdk;

import com.zxy.st.lv1.jdk.custom.GPMeipo;
import sun.misc.ProxyGenerator;

import java.io.FileOutputStream;

/**
 * @author : wb-zxy450245
 * @date :  2019/10/10
 */
public class TestFindLove {
    public static void main(String[] args) {
        //new Xiaoxingxing().findLove(); //直接调用
        /* 使用jdk自带的动态代理 调用目标方法
        Person meipo = (Person) new Meipo().getInstance(new Xiaoxingxing());
        meipo.findLove();*/

        //new GPMeipo().getInstance(new Xiaoxingxing());
        //自定义动态代理实现调用目标方法
        Person meipo = (Person) new GPMeipo().getInstance(new Xiaoxingxing());
        meipo.findLove();
        /*
        * 原理:
        * 1. 拿到 被代理的类实例,并且获取它的接口
        * 2. 创建新的代理类,并且实现被代理类的接口
        * 3. 并且同时获取到被代理类的引用
        * 4. 编译生成 新代理类的 class字节码
        * 5. 并加载到jvm中
        * */
        /*try {
            //获取字节码内容,这个字节码是 jvm自己创建的代理对象的自己码,自动生成的代理类
            byte[] data = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{Person.class});
            FileOutputStream os = new FileOutputStream("D:\\studyProject\\fate-second\\src\\main\\java\\com\\zxy\\st\\lv1\\$Proxy0.class");
            os.write(data);
            os.close();

        } catch (Exception ex) {
            ex.printStackTrace();
        }*/


    }
}

二、以下为核心自定义代码

  1. 自定义 接口 InvocationHandler -》 GPInvocationHandler

需定义 invke方法,与jdk源码中的定义相同。

package com.zxy.st.lv1.jdk.custom;

import java.lang.reflect.Method;

/**
 * @author : wb-zxy450245
 * @date :  2019/10/10
 */
public interface GPInvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
  1. 自定义的 代理公共类 GPProxy

里面需要做:

  • 生成新代理类代码,通过反射技术,将代码拼接后,写入新的java类文件
  • 通过 proxy 自带的功能,编译java文件,生成class 文件。
  • 通过自定义的 GPClassLoader, 加载class 文件,并且将class文件中的类信息,加载到jvm中,并且自动生成的代理类的定义。
  • 通过 动态代理类的定义 获取到 构造方法,然后进行实例化,获取到代理类的实例,并且返回
package com.zxy.st.lv1.jdk.custom;

import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

/**
 * 生成代理对象的代码
 *
 * @author : wb-zxy450245
 * @date :  2019/10/10
 */
public class GPPorxy {

    private static String ln = "\r\n";

    public static Object newProxyInstance(GPClassLoader classLoader, Class<?>[] interfaces, GPInvocationHandler h) throws IllegalArgumentException {
        try {
            // 1. 生成源代码
            String proxySrc = generateSrc(interfaces[0]);

            //2. 将生成的源代码 输出到磁盘,保存为.java 文件
            String filePath = GPPorxy.class.getResource("").getPath();
            File f = new File(filePath + "$Proxy0.java");

            FileWriter fw = new FileWriter(f);
            fw.write(proxySrc);
            fw.flush();
            fw.close();


            //3. 将.java文件编译成 class 文件
            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
            StandardJavaFileManager manager = compiler.getStandardFileManager(null, null, null);
            Iterable iterable = manager.getJavaFileObjects(f);

            //编译 代码。 最终获得 class 文件。
            JavaCompiler.CompilationTask task = compiler.getTask(null, manager, null, null, null, iterable);
            task.call();
            manager.close();

            //4. 将class 文件内容动态加载到 jvm中
            Class proxyClass = classLoader.findClass("$Proxy0");

            //4. 返回被代理后的 代理对象
            Constructor c = proxyClass.getConstructor(GPInvocationHandler.class);
            f.delete();
            return c.newInstance(h);

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 生成源代码
     *
     * @return
     */
    private static String generateSrc(Class<?> interfaces) {

        StringBuffer src = new StringBuffer();
        //package com.zxy.st.lv1.jdk.custom
        src.append("package com.zxy.st.lv1.jdk.custom;" + ln);
        src.append("import java.lang.reflect.Method; " + ln);
        src.append("public class $Proxy0 implements " + interfaces.getName() + "{" + ln);

        src.append("GPInvocationHandler h;" + ln);
        src.append("public $Proxy0(GPInvocationHandler h) {" + ln);
        src.append("this.h = h ;" + ln);

        src.append("}");
        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);
            /*if (m.getReturnType().getName().equals("void")){
                src.append("return null")
            }*/
            src.append("}" + ln);
        }


        src.append("}");


        return src.toString();
    }
}
  1. 自定义的 clssLoader 类 GPClassLoder
  • 获取到 代理公共类 生成的代理类的class 文件。
  • 将文件内容读取,并且将文件中的类加载到jvm中。
  • 返回类的定义 ``` package com.zxy.st.lv1.jdk.custom;

import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException;

/**

    1. class 文件。已经获得。
    1. 编译
    1. 重新load 到 jvm *
  • @author : wb-zxy450245
  • @date : 2019/10/10 */ public class GPClassLoader extends ClassLoader {

    private File baseDir;

    public GPClassLoader() {

     String basePath = GPClassLoader.class.getResource("").getPath();
     this.baseDir = new File(basePath);
    

    }

@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
    String className = GPClassLoader.class.getPackage().getName() + "." + name;

    if (baseDir.exists()) {
        //找到编译好的class 文件
        File classFile = new File(baseDir, name.replaceAll("\\.", "/") + ".class");
        if (classFile.exists()) {

            //如果源文件存在。则进行加载到 jvm中
            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);
                }
                classFile.delete();
                //jvm 提供 class 加载到 jvm的方法
                return defineClass(className, out.toByteArray(), 0, out.size());

            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (in != null) {
                    try {
                        in.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (null != out) {
                    try {
                        out.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }


        }

    }


    return super.findClass(name);
}

}



4. 代理类  媒婆 GPMeipo

模仿 正常情况下写的代理类,他继承了自定义的  handler 接口,并且完成以下能力

- 获取到 系统创建的新的代理类的实例。
- 定义了 invke 方法。 method.invoke(this.target, args);  执行了被代理类的 方法。

package com.zxy.st.lv1.jdk.custom;

import com.zxy.st.lv1.jdk.Person;

import java.lang.reflect.Method; import java.lang.reflect.Proxy;

/**

  • @author : wb-zxy450245
  • @date : 2019/10/10 */ public class GPMeipo implements GPInvocationHandler {

    private Person target;

    public Object getInstance(Person target) {

     this.target = target;
     Class<? extends Person> clazz = target.getClass();
     return GPPorxy.newProxyInstance(new GPClassLoader(), clazz.getInterfaces(), this);
     // return null;
    

    }

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    System.out.println("invoke 被执行-开始");
    method.invoke(this.target, args);
    System.out.println("invoke 被执行-结束");
    return null;
}

}

```

以上是自定义的 动态代理实现的原理。