手写实现JDK的动态代理

Person接口

package com.zhoucong.proxy.jdk;

public interface Person {

//    寻找真爱
    void findlove();

}

人物实现类

package com.zhoucong.proxy.jdk;

public class Zhangsan implements Person{

    @Override
    public void findlove() {
        System.out.println("我叫张三,性别女,我找对象的要求如下:\n");
        System.out.println("高富帅");
        System.out.println("有房有车");
        System.out.println("身高180cm以上,体重70kg");
    }

}

自定义InvocationHandler接口

package com.zhoucong.custom;

import java.lang.reflect.Method;

public interface GPInvocationHandler {

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

}

代理类

package com.zhoucong.custom;

import java.lang.reflect.Method;

import com.zhoucong.proxy.jdk.Person;

public class GPMeiPo implements GPInvocationHandler{

    private Person target;

//  获取被代理人的个人资料
    public Object getInstance(Person target) throws Exception {
        this.target = target;
        Class clazz = target.getClass();
        System.out.println("被代理对象的class是:"+ clazz);
        return GPProxy.newProxyInstance(new GPClassLoader(), clazz.getInterfaces(), this);

    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
         System.out.println("我是媒婆!");
         System.out.println("开始信息海选");
         System.out.println("-------------");
         method.invoke(this.target, args);
         System.out.println("-------------");
         System.out.println("如果合适的话,就准备办事");
         return null;
    }

}

生成代理对象类

package com.zhoucong.custom;

import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;

/**
 * 生成代理对象的代码
 *
 * @author ZhouCong
 *
 */
public class GPProxy {

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

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

//        2.将生成的源代码输出到磁盘,保存.java文件
            String path = GPProxy.class.getResource("").getPath();
            File f = new File(path + "$Proxy0.java");
            FileWriter fw = new FileWriter(f);
            fw.write(proxySrc);
            fw.flush();
            fw.close();

//        3.编译源代码,并且生成.class文件
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        StandardJavaFileManager manager = compiler.getStandardFileManager(null, null, null);
        Iterable iterable = manager.getJavaFileObjects(f);
        CompilationTask task = compiler.getTask(null, manager, null, null, null, iterable);
        task.call();
        manager.close();

//        4.将class文件中的内容,动态加载到JVM中
        Class<?> proxyClass = loader.findClass("$Proxy0");
        Constructor<?> constructor = proxyClass.getConstructor(GPInvocationHandler.class);
        f.delete(); //删除生成的Java文件

//        5.返回被代理后的代理对象
        return constructor.newInstance(h);

        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }

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

        StringBuffer src = new StringBuffer();
        src.append("package com.zhoucong.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("}" + ln);

        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);
            src.append("}" + ln);
        }

        src.append("}");
        return src.toString();
    };
}

自定义ClassLoader类

package com.zhoucong.custom;

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

/**
 * 代码生成、编译、重新动态load到JVM中
 * @author ZhouCong
 *
 */
public class GPClassLoader extends ClassLoader{

    private File baseDir;

    public GPClassLoader() {
        String path = GPClassLoader.class.getResource("").getPath();
        this.baseDir = new File(path);
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        String className = GPClassLoader.class.getPackage().getName() + "." + name;
        if(baseDir != null) {
            File classFile = new File(baseDir,name.replaceAll("\\.", "/")+".class");
            if(classFile.exists()) {
                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);
                    }
                    return defineClass(className,out.toByteArray(),0,out.size());

                }catch (Exception e) {
                    e.printStackTrace();
                }finally {

                    if(null != in) {
                        try {
                            in.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    if(null != out) {
                        try {
                            out.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
//                    删除class文件
                    classFile.delete();
                }
            }

        }

        return null;
    }

}

运行类

package com.zhoucong.proxy.jdk;

import com.zhoucong.custom.GPMeiPo;

public class TestFindLove {

    public static void main(String[] args) {

        try {

            Person obj = (Person) new GPMeiPo().getInstance(new Zhangsan());
            System.out.println(obj.getClass());
            obj.findlove();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

原文地址:https://www.cnblogs.com/itzhoucong/p/12144339.html

时间: 2024-10-09 11:00:21

手写实现JDK的动态代理的相关文章

JDK动态代理深入理解分析并手写简易JDK动态代理(上)

原文引用https://www.dazhuanlan.com/2019/08/26/5d6300df6f20f/ 博客真的是好几个月没更了,2019新年第一篇,继续深入动态代理,前两篇简单分析了动态代理的实现原理之后,这次继续深入了解具体的实现方式,并手写一套简易的动态代理已加强理解: 本博客关于Java动态代理相关内容直达链接: JDK动态代理浅析 Cglib动态代理浅析 JDK动态代理深入理解分析并手写简易JDK动态代理(上) JDK动态代理深入理解分析并手写简易JDK动态代理(下) 博客真

JDK,cglib动态代理-AOP学习

8.利用动态代理模式重构hibernate 动态代理模式: 1.产生的代理对象和目标对象实现了共同的接口 jdk动态代理 2.代理对象是目标对象的子类 hibernate: Person person = session.load(Person.class,1L);  javassisit spring:cglib动态代理 jdk的动态代理: 1.因为是用jdk的API做到的 2.代理对象是动态产生的 cglib产生的代理类是目标类的子类 注意事项: 1.拦截器中invoke方法体的内容就是代理

JDK的动态代理与cglib动态代理

JDK的动态代理与cglib动态代理 两种代理模式: 动态代理:代理类不存在,在程序运行过程中,动态生成代理类和代理类对象,再通过代理对象调用目标对象 静态代理(装饰者模式):代理类是提前创建好的,直接创建代理类对象,再通过代理对象调用目标对象 一.JDK动态代理 jdk的动态代理是基于接口的动态代理,要求目标对象必须实现至少一个接口,核心API是java.lang.reflect.Proxy类的newProxyInstance方法. Object proxy = Proxy.newProxyI

使用Jdk实现动态代理

一).创建动态代理的步骤 1.主题接口 2.代理类 3.真实类 4.使用类 1)主体接口中定义了代理类和真实类的的公共接口方法,代理类和真实类分别实现主体接口,真实类实现了接口方法的具体逻辑,代理类也实现了同样的接口方法,在方法中调用真实类的逻辑,相当于拿到了被代理人的授权,执行被代理人拥有的功能. 2)在实用类中,利用java的多态特性,使用公共接口,接收代理类,接收代理类对象,使用代理类调用公共方法,实现真实类的具体逻辑. 二).使用jdk实现动态代理 一.为什么要使用动态代理? 1).原有

继承?静态代理?写一个自己的动态代理吧

[ 需求分析 ] 在我们实际开发中常常会遇到这样的问题:记录一个类的方法运行时间,以分析性能.一般我们的做法是先在类的开始记录一个开始时间,然后在类的结束记录一个结束时间,二者相减就可以获取我们想要的结果.但是很多时候这些类已经打了jar包,我们无法直接修改源码,这个时候我们应该怎么办呢? 下文使用Tank的移动需要统计时间.记录日志来模拟需求场景,假定Moveable.Tank类无法修改. interface:Moveable public interface Moveable { publi

Java--简单的Spring AOP配置以及AOP事物管理,JDK/GCLib动态代理

一.看一下简单的通过XML的AOP配置 1.首先创建一个简单的Student类 public class Student { private Integer age; private String name; public void setAge(Integer age) { this.age = age; } public Integer getAge() { System.out.println("Age : " + age); return age; } public void

CGLib与JDK的动态代理

一.CGLib 简介 CGLib (Code Generation Library) 是一个强大的,高性能,高质量的Code生成类库.它可以在运行期扩展Java类与实现Java接口.Hibernate用它来实现PO字节码的动态生成.CGLib比 Java 的 java.lang.reflect.Proxy 类更强的在于它不仅可以接管接口类的方法,还可以接管普通类的方法. CGLib 的底层是Java字节码操作框架 -- ASM.CGLib就是封装了ASM,简化了ASM的操作,实现了在运行期动态生

JDK的动态代理为什么必须要使用接口与使用CGLIB动态代理

一.JDK的动态代理为什么必须要使用接口 JDK的代理Proxy必须要使用接口,才可以实现对方法的拦截.为什么呢?先让我们看一个JDK动态代理的示例: 接口类: public interface IPerson { public void sayHi(String nm); } 接口实现类: public class Person  implements IPerson{ public Person(){//构造 } private String name; public Person(Stri

Spring的AOP实现使用的JDK的动态代理必须使用接口

今天,在项目中遇到一个问题,情况是这样的:在一个项目中,我配置了一个用以处理任务的工厂类,然后将这个工厂类注入到其他的service类中进行使用.在Spring中的配置如下: <bean id="linkingDetectService" class="cn.vobile.service.linkingdetect.LinkingDetectServiceImpl"> <property name="taskPriority"