zoukankan      html  css  js  c++  java
  • 动态代理

    java动态代理的前提条件是,代理对象必须实现了某个接口。如果没有实现接口,就需要用cglib代理。

    构造代理类需要三个信息:

    • 目标类的类加载器 
    • 目标类实现的接口
    • 代理处理句柄

    生成的代理类 继承Proxy 并且 实现目标类的接口

    然后调用Proxy构造方法,设置处理句柄 InvokeHandler h

    假设目标类: TargetImp

    目标类接口: Target

    自定义处理句柄: MyInvoke implements InvocationHandler

    那么代理类 $taget0 大概就是这样的结构:

    $taget0 extends Proxy implements Target {

      Medhod m1;

      Medhod m2;

      ...

      Medhod m1;

     //.....

    }

    InvocationHandler 设置时通过调用Proxy的newProxyInstance(Object ,Method , Object[] ) 

    然后该方法内部调用Proxy的构造方法,Proxy(InvocationHandler h)设置处理句柄.

    其实所有的代理处理逻辑都在InvocationHandler  的 invoke方法中。

    $taget0 执行方法其实就是调用invoke(this,m1,args)类似这样

    $taget0内部会对应每一个方法生成一个方法的句柄 Method m1 ...

    然后执行时会调用父类InvocationHandler属性的invoke方法

    super.h.invoke(this,m1,args);

    实例:

    接口 Target.java

    package proxy.dynamic;
    
    public interface Target {
        public void say();
        public void play();
    }

    目标类 TargetImp.java

    package proxy.dynamic;
    
    public class TargetImp implements Target{
        public void say(){
            System.out.println("Target say()");
        }
    
        public void play(){
            System.out.println("Target play()");
        }
    }

    处理逻辑 MyInvoke.java

    package proxy.dynamic;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    
    public class MyInvoke implements InvocationHandler{
        Object target;
        public MyInvoke(Object target){
            this.target = target;
        }
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            if (method.getName() == "say") {
                System.out.println("begain say()");
            }
            if (method.getName() == "play") {
                System.out.println("begain play()");
            }
            Object res = method.invoke(target, args);
            if (method.getName() == "say") {
                System.out.println("end say()");
            }
            if (method.getName() == "play") {
                System.out.println("end play()");
            }
            return res;
        }
    }

    测试类 DynamicProxy.java

    package proxy.dynamic;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Proxy;
    
    public class DynamicProxy {
        public static void main(String[] args) {
            final Target target = new TargetImp();
            InvocationHandler myInvoke = new MyInvoke(target);
            Target targetProxy = (Target) Proxy.newProxyInstance(TargetImp.class.getClassLoader(),TargetImp.class.getInterfaces(),myInvoke);
    
            targetProxy.say();
            targetProxy.play();
    
        }
    }

    执行结果:

    begain say()
    Target say()
    end say()
    begain play()
    Target play()
    end play()

    然后我们进一步看看代理生成的类在哪,在虚拟机中是什么样的结构

    这里用jdk提供的虚拟机调试工具 hsdb 调试

    先来看一下生成的类:

    我们看到生成了一个代理类$Proxy0, 下面看一下类的结构

     这里显示了:

    • $Proxy0 的父类
    • 实现的接口
    • 一些方法的句柄,
    • methods部分的一些方法被重写,内部会调用 invoke
    • 最先面是常量池的信息


    再继续,我们在深入的看一下 $Proxy0 产生的实例包含了什么信息

    可以看到$Proxy0实例 关联了一个 MyInvoke实例 。然后MyInvoke实例 关联了 目标对象 TargetImp

    总结:

    动态代理就是根据目标对象,产生一个 和目标对应拥有共同接口 且 继承了Proxy类的 类。

    具体代理逻辑,交给InvocationHandler 的实现类去处理。

  • 相关阅读:
    Vivado2014.3安装破解流程
    Win7、Win8、win10系统USB-Blaster驱动程序无法安装的解决办法
    Quartus II 与ModelSim-Altera联合仿真FFT IP核之FFT IP调用与自产生信号分析-lab2
    Quartus II 与ModelSim-Altera联合仿真FFT IP核之FFT IP调用与例程数据验证-lab1
    Quartus II 与ModelSim-Altera联合仿真FFT IP核之FFT IP核分析
    Quartus II 与ModelSim-SE联合仿真Shift_ram
    Quartus II 与ModelSim-Altera联合仿真PLL
    1st.初识GCC——关于GCC编译器的相关语法与介绍
    5th.NandFlash初接触——反正他说这几节课都是启发一下而已
    4th.关于MMU中的虚拟映射
  • 原文地址:https://www.cnblogs.com/justenjoy/p/9088555.html
Copyright © 2011-2022 走看看