• 动态代理


    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 的实现类去处理。

  • 相关阅读:
    JAVA中SpringMVC获取bean方法,在工具类(utils)注入service
    JAVA中json对象转JAVA对象,JSON数组(JSONArray)转集合(List)
    maven中pom文件中scope的作用
    页面图片懒加载、延迟加载(lazyload)
    js(jQuery)获取自定义data属性的值
    ubantu使用小结
    ipmitool管理工具
    大于2T的硬盘怎么分区
    lamp的动静分离部署
    keepalived脑裂问题
  • 原文地址:https://www.cnblogs.com/justenjoy/p/9088555.html
Copyright © 2020-2023  润新知