栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

手写jdk动态代理

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

手写jdk动态代理

手写jdk动态代理_笔记
  • 思路
  • 实现
    • MyInvocationHandler接口
    • MyClassLoader
    • MyProxy
  • 测试
    • 动态生成的类长这个样子

思路

先上一张图

对目标对象进行代理,本质其实是底层动态生成一个类加载到 jvm 中,该类将实现原目标对象的所有接口,重写所有方法,通过动态代理扩展功能,其实也可以理解为是通过重写扩展功能,下面就通过这个思路手写一个动态代理

实现

jdk动态生成代理对象步骤

  1. 创建目标对象
  2. 目标对象通过反射获取所有接口
  3. 动态生成Java源代码,实现所有接口
  4. 通过IO流生成Java文件
  5. 使用JavaCompiler类将Java文件编译成class文件
  6. 将生成的新类加载到jvm
  7. 获取该类构造器创建代理对象
MyInvocationHandler接口
package com.cml.proxy;

import java.lang.reflect.Method;


public interface MyInvocationHandler {
    
    Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
MyClassLoader
package com.cml.proxy;

import java.io.*;
import java.util.Objects;


public class MyClassLoader extends ClassLoader{
    private final File classPathFile;

    public MyClassLoader(){
        String classPath = Objects.requireNonNull(MyClassLoader.class.getResource("")).getPath();
        this.classPathFile = new File(classPath);
    }

    
    @Override
    protected Class findClass(String name) {

        String className = MyClassLoader.class.getPackage().getName() + "." + name;
        if(classPathFile  != null){
            File classFile = new File(classPathFile,name.replaceAll("\.","/") + ".class");
            if(classFile.exists()){
                try {
                    //将class文件转为字节数组
                    byte[] bytes = file2ByteArray(classFile);
                    //将字节数组转为Class对象返回
                    return defineClass(className,bytes,0,bytes.length);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

    
    private byte[] file2ByteArray(File file) throws Exception {
        FileInputStream in = new FileInputStream(file);
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        byte [] buff = new byte[1024];
        int len;
        while ((len = in.read(buff)) != -1){
            out.write(buff,0,len);
        }
        return out.toByteArray();
    }
}

MyProxy
package com.cml.proxy;

import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
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;
import java.util.Objects;


public class MyProxy {
    private static final String LN = "rn";

    public static Object newProxyInstance(MyClassLoader classLoader, Class[] interfaces, MyInvocationHandler h) {
        try {
            //1.动态生成java源代码,字符串拼接
            String src = generateSrc(interfaces);
            System.out.println(src);
            //2.IO流生成java文件
            String filePath = Objects.requireNonNull(MyProxy.class.getResource("")).getPath();
            File f = new File(filePath + "$MyProxy0.java");
            System.out.println(f);
            FileWriter fw = new FileWriter(f);
            fw.write(src);
            fw.flush();
            fw.close();

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

            JavaCompiler.CompilationTask task = compiler.getTask(null, manage, null, null, null, iterable);
            task.call();
            manage.close();

            //4.加载到JVM
            Class myProxyClass = classLoader.findClass("$MyProxy0");
            //5.获取动态生成的类的构造器
            Constructor c = myProxyClass.getConstructor(MyInvocationHandler.class);
            //加载完class文件删除生成的java源文件
            f.delete();

            //6.返回构造的代理对象
            return c.newInstance(h);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    
    private static String generateSrc(Class[] interfaces) {
        StringBuilder sb = new StringBuilder();
        sb.append(MyProxy.class.getPackage()).append(";").append(LN);
        sb.append("import ").append(interfaces[0].getName()).append(";").append(LN);
        sb.append("import java.lang.reflect.*;" + LN);
        sb.append("public class $MyProxy0 implements ").append(interfaces[0].getName()).append("{").append(LN);
        sb.append("MyInvocationHandler h;" + LN);
        sb.append("public $MyProxy0(MyInvocationHandler h) { " + LN);
        sb.append("this.h = h;");
        sb.append("}" + LN);
        for (Method m : interfaces[0].getMethods()) {
            Class[] params = m.getParameterTypes();
            StringBuilder paramNames = new StringBuilder();
            StringBuilder paramValues = new StringBuilder();
            StringBuilder paramClasses = new StringBuilder();

            for (int i = 0; i < params.length; i++) {
                Class clazz = params[i];
                String type = clazz.getName();
                //参数变量名
                String paramName = "var" + i;
                //参数列表拼接类型和变量名
                paramNames.append(type).append(" ").append(paramName);
                //变量名拼接作为Object数组,作为invoke的参数
                paramValues.append(paramName);
                //拼接参数类型作为Class数组,用于反射查找对应的方法对象
                paramClasses.append(clazz.getName()).append(".class");
                if (i < params.length - 1) {
                    paramNames.append(",");
                    paramClasses.append(",");
                    paramValues.append(",");
                }
            }

            sb.append("public ").append(m.getReturnType().getName()).append(" ").append(m.getName()).append("(").append(paramNames).append(") {").append(LN)
                .append("try{" + LN)
                .append("Method m = ").append(interfaces[0].getName()).append(".class.getMethod("").append(m.getName()).append("",new Class[]{").append(paramClasses).append("});").append(LN)
                .append(hasReturnValue(m.getReturnType()) ? "return (" + m.getReturnType().getName() + ")" : "").append("this.h.invoke(this,m,new Object[]{").append(paramValues).append("})").append(";").append(LN)
                .append("}catch(Error er) {throw er; }").append(LN)
                .append("catch(Throwable e){").append(LN)
                .append("throw new UndeclaredThrowableException(e);" + LN)
                .append("}").append(LN)
                .append("}");
        }
        sb.append("}" + LN);
        return sb.toString();
    }


    
    private static boolean hasReturnValue(Class clazz) {
        return clazz != void.class;
    }

}

测试

定义接口InterfaceOne

package com.cml.test;

public interface InterfaceOne {
    String show(String s1, String s2);

    String hello(String s1);
}

接口实现类

package com.cml.test;

public class ImplOne implements InterfaceOne {

    @Override
    public String show(String s1, String s2) {
        System.out.println("InterfaceOne >> ImplOne >> show");
        return s1 + s2;
    }

    @Override
    public String hello(String s1) {
        return s1;
    }

}

定义通知类

package com.cml.test;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;


public class Aspect {
    public void before(){
        System.out.println("前置通知");
    }
    
    public void afterReturning(Object ret){
        System.out.println("后置通知, 返回值为-->" + ret);
    }
    
    public void afterThrowing(Throwable e){
        System.out.println("抛出异常通知 ,异常信息: " + e.getMessage());
    }
    
    public void after(){
        System.out.println("最终通知:finally里面的代码,发生异常也会执行。。。");
    }


    public Object around(Object target, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException {
        System.out.println("环绕通知      前");
        Object ret = method.invoke(target, args);
        System.out.println("环绕通知      后");
        return ret;
    }
}

实现MyInvocationHandler接口

package com.cml.test;

import com.cml.proxy.MyClassLoader;
import com.cml.proxy.MyInvocationHandler;
import com.cml.proxy.MyProxy;

import java.lang.reflect.Method;


public class MyDynamicProxy implements MyInvocationHandler {
    private Object target;
    
    private Aspect aspect;
    //设置通知类
    public void setAspect(Aspect aspect) {
        this.aspect = aspect;
    }

    
    public Object createProxyInstance(Object target) {
        this.target = target;
        return MyProxy.newProxyInstance(new MyClassLoader(), target.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object ret = null;
        try {
            aspect.before();
            ret = aspect.around(target, method, args);
            aspect.afterReturning(ret);
        } catch (Exception e) {
            aspect.afterThrowing(e);
        } finally {
            aspect.after();
        }
        return ret;
    }
}

执行

package com.cml.test;


public class Test {
    public static void main(String[] args) {
        MyDynamicProxy myDynamicProxy = new MyDynamicProxy();
        myDynamicProxy.setAspect(new Aspect());
        InterfaceOne interfaceOne = (InterfaceOne) myDynamicProxy.createProxyInstance(new ImplOne());
        interfaceOne.show("show", "cml");
        System.out.println(interfaceOne.getClass());
        System.out.println(interfaceOne.getClass().getSuperclass());
    }
}

结果

动态生成的类长这个样子

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/425030.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号