模拟JDK动态代理的内部实现

代理模式的定义:

   为其他对象提供一种代理,以控制对这个对象的访问。代理对象起到了一个中介的作用,可以去掉功能服务、增加额外服务
  JDK动态代理:
  1.只能代理实现了接口的类
  2.没有实现接口的类不能实现JDK的动态代理

  CGLIB动态代理:
  1.针对类实现代理的
  2.对指定目标类产生一个子类,通过方法拦截技术拦截所有父类方法的调用

在这里插入图片描述
Java动态代理类位于java.lang.reflect包下,一般主要涉及到以下两个类:
    1. Interface InvocationHandler:该接口中仅定义了一个方法
    public object invoke(Object obj,Method methdo,Object[] args)在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法,args为该方法的参数数组。这个抽象方法在代理类中动态实现。
    2.Proxy:该类为动态代理类
    static Object newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h):返回代理类的一个实例,返回后的代理类可以当作被代理类使用(可使用被代理类的在接口中声明过的方法)。

实现思路

实现功能:通过Proxy的newProxyInstance返回代理对象(代理任意对象任意方法)
1.声明一段源码(动态产生代理)
2.编译源码(JDK Compiler API),产生新的类(代理类)
3.将这个类load到内存中,产生一个新的对象(代理对象)
4.return代理对象

实现代码
//被代理类
public class Car implements Moveable {
    public void move() {
        System.out.println("汽车开始行驶!");
    }
}
//实现的接口
public interface Moveable {
    void move();
}

//Proxy代理类(主要代码)
//代理类
public class Proxy {
    public static Object newProxyInstance(Class infce, InvocationHandler h) throws Exception{

        String rt = "\r\n";
        String methodStr = "";
        
        for (Method m : infce.getMethods()){
        
            //methodStr为重写的需要代理方法(car.move())
            methodStr += "   //@Override" + rt +
                    "   public void " + m.getName() + " (){" + rt +
                    "try{" + rt +
                    "Method md = " + infce.getName() + ".class.getMethod(\"" + m.getName() + "\");" + rt +
                    "h.invoke(this,md);" + rt +
                    "}catch (Exception e){" + rt +
                    "e.printStackTrace();" + rt +
                    "}" + rt +
                    "   }";
        }
        
        //拷贝源代码(CarTimeProxy类中的代码) 更改文件名为$Proxy0(模仿jdk命名) 修改类名 方法名 参数为传入获取
        String str =
                "package com.demo.proxy;" + rt +
                "import java.lang.reflect.Method;" + rt +
                "import com.demo.proxy.InvocationHandler;" + rt +
                "public class $Proxy0 implements " + infce.getName() + "{" + rt +

                "private  InvocationHandler h;" + rt +

                "public $Proxy0(InvocationHandler h) {" + rt +
                "        super();" + rt +
                "       this.h = h;" + rt +
                "   }" + rt +
                //methodStr为重写的需要代理方法
               methodStr + rt +
                "};";

        //准备编译.java文件
        //文件路径 取当前应用(项目)所在路径 放到bin目录下方便编译
        String filename = System.getProperty("user.dir") + File.separator + "bin" + File.separator + "com" +
                File.separator + "demo" + File.separator + "proxy" + File.separator + "$Proxy0.java";
                
        //生成文件
        File file = new File(filename);
        
        //源码生成到java文件中(需要导commons-io的jar包)
        FileUtils.writeStringToFile(file, str);
        
        //编译
        //拿到当前系统的编译器
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        
        //创建文件的管理者(参数1.诊断监听器 2.3国际化参数 简单起见设为null)
        StandardJavaFileManager fileManager = compiler.getStandardFileManager(null,null,null);
        
        //获取文件(根据文件名得到管理文件的宿主)
        Iterable units = fileManager.getJavaFileObjects(filename);
        
        //编译任务 返回编译的一个任务
        JavaCompiler.CompilationTask t = compiler.getTask(null, fileManager, null, null, null, units);
        
        //将生成的$Proxy0进行编译等同javac命令
        t.call();
        fileManager.close();
        
        //编译好的文件load到内存
        ClassLoader classLoader = ClassLoader.getSystemClassLoader();
        Class c = classLoader.loadClass("com.demo.proxy.$Proxy0");
        
        //根据构造器初始化 产生代理类并返回 
        Constructor constructor = c.getConstructor(InvocationHandler.class);
        return constructor.newInstance(h);
    }
}
//拷贝模仿的源代码类(代理类)
public class CarTimeProxy implements Moveable {

    private  Moveable moveable;

    public CarTimeProxy(Moveable moveable) {
        super();
        this.moveable = moveable;
    }

    @Override
    public void move() {
        long startTime = System.currentTimeMillis();
        System.out.println("汽车开始行驶---》");
        moveable.move();
        long endTime = System.currentTimeMillis();
        System.out.println("汽车结束行驶。。。行驶时间:" + (endTime - startTime) + "ms!");
    }
}
//事务处理器接口代码(InvocationHandler)
//事务处理器(newProxyInstance中使用)
public interface InvocationHandler {
    void invoke(Object o, Method method);
}
//事务处理器实现类代码

代理类并不能做具体的事,声明一个Handler,由它接管实际的工作,具体业务在Handler中实现

//事务处理器实现类
public class TimeHandler implements InvocationHandler {

    //被代理对象(调用方法)
    private Object targer;

    public TimeHandler(Object targer) {
        super();
        this.targer = targer;
    }

    //参数o 代理对象 其实调用的是被代理对象(通过构造方法初始化)
    @Override
    public void invoke(Object o, Method method) {
        try {
            long startTime = System.currentTimeMillis();
            
            System.out.println("汽车开始行驶---》");
            
            method.invoke(targer);
            
            long endTime = System.currentTimeMillis();
            
            System.out.println("汽车结束行驶。。。行驶时间:" + (endTime - startTime) + "ms!");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
//测试类代码
public class TestProxy {
    public static void main(String[] args) throws Exception {
		//new Car()为被代理对象 moveable为代理对象
        InvocationHandler invocationHandler = new TimeHandler(new Car());
        Moveable moveable = (Moveable) Proxy.newProxyInstance(Moveable.class, invocationHandler);
        moveable.move();
    }
   /* 
   Car类被代理前:
   		汽车开始行驶!
    */
    /*
    Car类被代理后:
    汽车开始行驶---》
	汽车开始行驶!
	汽车结束行驶。。。行驶时间:0ms!
    */
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值