实现自己的动态代理,类似JDK动态代理

本文详细介绍了Java动态代理的实现原理,包括定义接口、实现类、自定义类加载器、自定义InvocationHandler接口以及生成代理对象的过程。通过字节码重组技术,实现了动态生成代理类并加载到JVM中。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

代理模式必须满足的条件

1,两个角色,代理对象和被代理对象

2,被代理对象的事情必须要做,但是他自己又不想做

3,代理对象必须知道被代理代理对象的信息(持有被代理对象的引用)

总结:动态代理的本质就是字节码重组

 

1,定义一个接口

public interface Person2 {
    
    public void findLove();

}

实现类

public class Zhangsan implements Person2{

    private String name = "张三";
    private String sex = "男";
    
    public void findLove() {
        System.out.println("我的名字是:"+this.name+",我的性别是:"+this.sex);
        System.out.println("1,我要寻找的对象是白富美");
        System.out.println("2,我的对象要有房有车");
    }

}

2,实现自己的类加载器

public class ZLClassLoader extends ClassLoader{
    
    /**
     * 重写类的加载方式,将字节码加载到JVM中来
     */
   @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        
        //在URI中,包名及类名每一层中间都是用”/”来分隔的。

       //在加载资源时,也是需要使用完整的类名,但是每层中间的”/”需要替换成”.”才行。
        String basePath = "D:/ws_sts/netty-test/target/classes/com/zl/test/custom/"+name+".class";
        
        File classFile = new File(basePath);
        
        if(classFile.exists()) {
            FileInputStream fis = null;
            ByteArrayOutputStream bos = null;
            try {
                fis = new FileInputStream(classFile);
                bos = new ByteArrayOutputStream();
                
                byte[] buff = new byte[1024];
                int len =0;
                while((len = fis.read(buff))!=-1) {
                    bos.write(buff, 0, len);
                }
                
                String className = ZLClassLoader.class.getPackage().getName()+"."+name;
                System.out.println("className===>"+className);
                //JVM读取字节码
                Class<?> clz = defineClass(className, bos.toByteArray(), 0, bos.size());
                
                System.out.println("加载文件到JVM完毕。。。。");
                
                //删除字节码文件,无感知
                classFile.delete();
                
                return clz;
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                if(fis!=null) {
                    try {
                        fis.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                
                if(bos!=null) {
                    try {
                        bos.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        return null;
    }
}

 

3,定义自己的ZLInvocationHandler 接口

public interface ZLInvocationHandler {
    
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable;

}

 

4,

public class ZLProxy {
    
    private static String ln = "\r\n";

    /**
     * 生成代理类的实例
     *
     * @param zlloader
     * @param interfaces
     * @param zlhandler
     * @return
     * @throws IllegalArgumentException
     */
    public static Object newProxyInstance(ZLClassLoader zlloader, Class<?>[] interfaces, ZLInvocationHandler zlhandler)
            throws IllegalArgumentException {
        
        try {
            // 1动态生成java源码
            String src = generateSrc(interfaces[0]);
            //输出去看下是否语法编译通过
            String path = "D:/ws_sts/netty-test/target/classes/com/zl/test/custom/";
            File srcfile = new File(path +"$Proxy0.java");
            System.out.println(srcfile.getAbsolutePath());
            FileWriter fw = new FileWriter(srcfile);
            fw.write(src);
            fw.flush();
            fw.close();
            
            // 2将生成的源文件编译为class字节码
            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
            StandardJavaFileManager standardFileManager = compiler.getStandardFileManager(null, null, null);
            Iterable<? extends JavaFileObject> iter = standardFileManager.getJavaFileObjects(srcfile);
            CompilationTask task = compiler.getTask(null, standardFileManager, null, null, null, iter);
            task.call();//生成class 文件
            standardFileManager.close();
            
            //删除源文件,实现无感知的动态生成文件
            srcfile.delete();
            
            // 3将字节码加载到JVM
            Class<?> clz = zlloader.findClass("$Proxy0");
            // 4反射生成代理对象
            Constructor<?> c = clz.getConstructor(ZLInvocationHandler.class);
            return  c.newInstance(zlhandler);
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        return null;
    }

    /**
     * 动态生成源码
     *
     * @return
     */
    public static String generateSrc(Class<?> interfaces) {
        StringBuffer src = new StringBuffer();
        src.append("package com.zl.test.custom;").append(ln);
        src.append("import java.lang.reflect.*;").append(ln).append(ln);
        src.append("public class $Proxy0 implements "+interfaces.getName()+"{"+ln);
        src.append("\t").append("private ZLInvocationHandler h;"+ln).append(ln);
        src.append("\t").append("public $Proxy0(ZLInvocationHandler h){"+ln);
        src.append("\t").append("\t").append("this.h=h;"+ln);
        src.append("\t").append("}"+ln).append(ln);
        //获取目标类的方法
        for(Method m :interfaces.getMethods()) {
            src.append("\t").append("public "+ m.getReturnType().getSimpleName() + " "+m.getName() +"(){").append(ln);
            src.append("\t").append("\t").append("try{").append(ln);
            src.append("\t").append("\t\t").append("Method mm = "+interfaces.getName()+".class.getMethod(\""+m.getName()+"\", new Class[]{});").append(ln);
            src.append("\t").append("\t\t").append("this.h.invoke(this, mm ,null);").append(ln);
            src.append("\t").append("\t").append("}catch(Throwable  e){e.printStackTrace();}").append(ln);
            src.append("\t").append("\t").append("return;").append(ln);
            src.append("\t").append("}").append(ln);
        }
        src.append("}"+ln);
        
        return src.toString();
    }

}

 

5,生成代理对象

public class CusMeiPo implements ZLInvocationHandler{

    private Person2 target;
    
    /**
     * 生成一个代理对象
     * @return
     */
    public Object getInstance(Person2 target) {
        this.target = target;
        Class<?> clz = target.getClass();
        System.out.println("被代理的对象是==》"+clz);

      //这里第三个参数this,也就是当前类,传递给代理类(动态生成的类),

//就形成了一个类似回调的方式,当前类的Invoke方法才的得以执行
        return ZLProxy.newProxyInstance(new ZLClassLoader(), clz.getInterfaces(), this);
    }
    
    
    
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        
        System.out.println("媒婆开始收费。。。。");

        method.invoke(this.target, args);
        
        System.out.println("媒婆收费牵线任务完毕。。。。。");
        return null;
    }

}

测试:

public class Test {
    
    public static void main(String[] args) {
        
        Person2 target = new Zhangsan();
        
        Person2 proxy= (Person2) new CusMeiPo().getInstance(target);
    
        proxy.findLove();
    }

}

测试结果:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值