动态代理源码解析(代理类解析)

动态代理源码解析

动态代理是什么?

动态代理是一种强大的功能,它可以在运行时动态创建一个类,实现一个或多个接口,可以在不修改原有类的基础上动态为通过该类获取的对象添加方法、修改行为,这么描述比较抽象,但是它实际用在许多的开源框架之中像Spring, Mybtis, Hibernate,等

动态代理剖析

既然这个在运行时动态创建一个类,实现一个或多个接口,那我们就把这个类导出来解析下

  1. 对于动态代理(JDK)的写法就不在赘述了,下面是一个很简单的Demo,就是为了引出代理类的:
/**
 * <Description> <br>
 *
 * @author shi.yuwen<br>
 * @version 1.0<br>
 * @see proxy2 <br>
 */
public class ProxyTest {
    interface Animal {
        void play ();
    }
    class Dog implements Animal {
        @Override
        public void play() {
            System.out.println("狗狗玩飞碟!");
        }
    }

    static class ProxyFactory {
        public static  <T> T getProxy(Object o) {
            return (T) Proxy.newProxyInstance(o.getClass().getClassLoader(), o.getClass().getInterfaces(),
                    new InvocationHandler() {
                        @Override
                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                            System.out.println("执行前调用");
                            Object result = method.invoke(o, null);
                            System.out.println("执行后调用");
                            return result;
                        }
                    });
        }
    }

    public static void main(String[] args) {
        ProxyFactory proxyFactory = new ProxyFactory();
        Animal dogProxy = (Animal)ProxyFactory.getProxy(new ProxyTest().new Dog());
        dogProxy.play();
    }
}

在执行main()前配置Run Configurations,加上java命令(这边jdk版本为1.801 高版本jdk这个参数可能会失效)

-Dsun.misc.ProxyGenerator.saveGeneratedFiles=true

在根目下会把内存中的代理类输出出来:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import proxy2.ProxyTest.Animal;

final class $Proxy0 extends Proxy implements Animal {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;

    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void play() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("proxy2.ProxyTest$Animal").getMethod("play");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}
  1. 首先看这个生成的代理类:继承了Proxy类实现了我们传入的接口(Animal)所以这就是为什么代理类能被接口接受的原因(多态)
  2. 往下是4个成员变量(Method)对于熟悉反射的人来说很容易理解,是什么时候赋值的呢,在这个类的最下面的静态代码块中(在装载类的时候变实现了初始化赋值)其中m1,m2,m4是Object的方法,m3是我们接口定义的方法play()
static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("proxy2.ProxyTest$Animal").getMethod("play");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
  1. 再往先看是一个构造方法它直接调用了父类构造方法,这边直接解释下:就是直接把我们写的InvocationHandler传入进来(就是Proxy.newProxyInstance的第三个参数)
  2. 往下equals(),toString()就不解释了,play()方法(由于实现了Animal接口)下面是这个代理类的核心代码:
super.h.invoke(this, m3, (Object[])null);
  1. 我们main()方法中代理类调用play方法会执行super.h.invoke方法上面也说过父类中已经有我们写的InvocationHandler 的实例了,那么便是执行我们自己重写的invoke(),传递三个参数this, m3, (Object[])null),便传递到了下面的参数
invoke(Object proxy, Method method, Object[] args)
  1. 所以代理类执行play()就会转而执行InvocationHandler的invoke(),而我们在invoke()中写的method.invoke()便会执行被代理对象的方法,所以在method.invoke()的上下文执行写before(),after(),便是相当于方法的增强.

这样已解析动态代理其实是很通俗易懂的,事实上也是如此代理模式确实算不上较难的设计模式

小结

本文解析了动态代理(基于JDK)的代理类的源码,像动态代理还有一种CGLib会在之后解析

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值