JDK动态代理原理

给目标对象提供一个代理对象,并由代理对象控制对目标对象的引用。

假设我们想请明星来唱歌,我们是先联系他的经纪人,在经纪人告诉明星,然后明星唱歌。其中经纪人就是代理。

静态代理与动态代理的区别

静态代理中的代理类是需要用户自己写的,这样代理类在程序运行前就已经存在了。

动态代理中的代理类是在程序运行中自动生成的。

//静态代理


//接口
public interface Fruit {
    void eat();
}

//实现类
public class Apple implements Fruit {
    public void eat() {
        System.out.println("吃苹果);
    }
}

//代理类
public class AppleProxy implements Fruit {
    private Apple apple;

    public AppleProxy (Apple apple) {
        this.apple = apple;
    }

    public void eat() {
        System.out.println("吃前先洗手");
        apple.eat();
        System.out.println("吃后也洗手");
    }

    public static void main(String[] args) {
        AppleProxy appleProxy = new AppleProxy(new Apple());
        appleProxy.eat();
    }
}

输出

吃前先洗手
吃苹果
吃后也洗手

JDK动态代理(包含一个类和一个接口)

     InvocationHandler接口

public interface InvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}

参数说明:

  • Object proxy:指被代理的对象
  • Method method:要调用的方法
  • Object[] args:方法调用时所需要的参数

可以将实现InvocationHandler接口的子类想象成一个最终操作类,替换掉AppleProxy。

  Proxy类

Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态的生成实现类

public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h);

参数说明:

  • ClassLoader loader:类加载器
  • Class<?>[] interfaces:得到全部的接口
  • InvocationHandler h:得到InvocationHandler接口的子类实例
//实现类
public class Apple implements Fruit {
    @Override
    public void eat() {
        System.out.println("吃苹果");
    }
}

//代理类
public class AppleProxy implements InvocationHandler {
    public Object object;

    public Object bind(Object object) {
        this.object = object;
        return Proxy.newInstance(object.getClass().getClassLoader(),     
                                 object.getClass().getInterfaces(), 
                                 this);
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result = null;
        System.out.println("执行方法之前");
        result = method.invoke(object, args);
        System.out.println("执行方法之后");
        return result;
    }

    public static void main(String[] args) {
        AppleProxy appleProxy = new AppleProxy();
        Fruit fruitProxy = (Fruit) appleProxy.bind(new Apple());
        fruitProxy.eat();
    }
}

输出
执行方法之前
吃苹果
执行方法之后

JDK的动态代理依靠接口实现,如果有些类并没有实现接口,则不能使用JDK代理,这就要使用CGLIB动态代理了。

 

CGLIB动态代理

cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现实现增强,但是因为采用是继承,所以不能对final类进行代理。

接口
public interface Fruit {
    void eat();
}

实现类
public class Apple implements Fruit {

    public void eat() {
        System.out.println("吃苹果");
    }
}

代理类
public class AppleProxy implements MethodInterceptor {
    private Object object;

    public Object getInstance(Object object) {
        this.object = object;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(this.object.getClass());
        //回调方法
        enhancer.setCallback(this);
        //创建代理对象
        return enhancer.create();
    }

    public Object intercept(Object object, Method method, 
                            Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("执行方法之前");
        methodProxy.invokeSuper(object, args);
        System.out.println("执行方法之后");
        return null;
    }

    public static void main(String[] args) {
        AppleProxy appleProxy = new AppleProxy();
        Apple apple = (Apple) appleProxy.getInstance(new Apple());
        apple.eat();
    }
} 

输出
执行方法之前
吃苹果
执行方法之后

JDK动态代理原理

生成代理对象的newProxyInstance()方法分析

 public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        //如果h为null则抛出NUllPointerException异常
        //之后所有的判断时候为null都用此方法
        Objects.requireNonNull(h);
        
        // 拷贝类实现的所有接口
        final Class<?>[] intfs = interfaces.clone();
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            //检查创建Proxy类所需的权限
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }

        /*
         * Look up or generate the designated proxy class.
         * 查找或产生代理类
         */
        Class<?> cl = getProxyClass0(loader, intfs);

        /*
         * Invoke its constructor with the designated invocation handler.
         * 调用它的构造函数
         */
        try {
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }
        
            // 获取代理类的构造器对象
            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
            //根据代理类的构造器对象创建代理类对象并返回
            return cons.newInstance(new Object[]{h});
        } catch (IllegalAccessException|InstantiationException e) {
            throw new InternalError(e.toString(), e);
        } catch (InvocationTargetException e) {
            Throwable t = e.getCause();
            if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            } else {
                throw new InternalError(t.toString(), t);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString(), e);
        }
    }

可以看到主要做了3件事情:

  • 生成代理类
  • 获取代理类的构造器对象
  • 根据构造器创建代理类对象

生成代理类

 /**
     * Generate a proxy class.  Must call the checkProxyAccess method
     * to perform permission checks before calling this.
     */
    private static Class<?> getProxyClass0(ClassLoader loader,
                                           Class<?>... interfaces) {

        if (interfaces.length > 65535) {//接口数不能超过65535
            throw new IllegalArgumentException("interface limit exceeded");
        }

        // If the proxy class defined by the given loader implementing
        // the given interfaces exists, this will simply return the cached copy;
        // otherwise, it will create the proxy class via the ProxyClassFactory
        // 如果缓存命中代理类则直接返回,否则用代理类工厂ProxyClassFactory创建代理类
        return proxyClassCache.get(loader, interfaces);
    }

/**
 * @param key       类加载器(可能为null)
 * @param parameter 接口数组(不能为null)
 */
public V get(K key, P parameter) {

    // 在缓存中没有找到会创建新的代理类
    Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
    Supplier<V> supplier = valuesMap.get(subKey);

    V value = supplier.get();
    return value;
}

apply方法的实现源码如下:

public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {

    Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
    // 验证
    for (Class<?> intf : interfaces) {
        Class<?> interfaceClass = null;
        try {
            interfaceClass = Class.forName(intf.getName(), false, loader);
        } catch (ClassNotFoundException e) {
        }
        if (interfaceClass != intf) {
            throw new IllegalArgumentException(
                intf + " is not visible from class loader");
        }
        if (!interfaceClass.isInterface()) {
            throw new IllegalArgumentException(
                interfaceClass.getName() + " is not an interface");
        }
        if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
            throw new IllegalArgumentException(
                "repeated interface: " + interfaceClass.getName());
        }
    }

    String proxyPkg = null;     // 代理类所在包
    int accessFlags = Modifier.PUBLIC | Modifier.FINAL;

    // 验证所有非公共的接口在同一个包内,公共的就无需处理
    for (Class<?> intf : interfaces) {
        int flags = intf.getModifiers();
        if (!Modifier.isPublic(flags)) {
            accessFlags = Modifier.FINAL;
            String name = intf.getName();
            int n = name.lastIndexOf('.');
            String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
            if (proxyPkg == null) {
                proxyPkg = pkg;
            } else if (!pkg.equals(proxyPkg)) {
                throw new IllegalArgumentException(
                    "non-public interfaces from different packages");
            }
        }
    }

    if (proxyPkg == null) {
        // if no non-public proxy interfaces, use com.sun.proxy package
        proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
    }

    // 生成代理类名,以$Proxy开头
    long num = nextUniqueNumber.getAndIncrement();
    String proxyName = proxyPkg + proxyClassNamePrefix + num;

    // 生成代理类字节码
    byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
        proxyName, interfaces, accessFlags);
    try {
        // 加载字节码,生成代理类对象
        return defineClass0(loader, proxyName,
                            proxyClassFile, 0, proxyClassFile.length);
    } catch (ClassFormatError e) {
        throw new IllegalArgumentException(e.toString());
    }
}

可以看到通过generateProxyClass方法生成代理类字节码,跟进该方法,发现又调用了generateClassFile()方法生成字节码,源码如下:

private byte[] generateClassFile() {
    // 添加hashCode、equals、toString方法
    this.addProxyMethod(hashCodeMethod, Object.class);
    this.addProxyMethod(equalsMethod, Object.class);
    this.addProxyMethod(toStringMethod, Object.class);
    Class[] var1 = this.interfaces;
    int var2 = var1.length;

    int var3;
    Class var4;
    // 添加接口中的方法
    for(var3 = 0; var3 < var2; ++var3) {
        var4 = var1[var3];
        Method[] var5 = var4.getMethods();
        int var6 = var5.length;

        for(int var7 = 0; var7 < var6; ++var7) {
            Method var8 = var5[var7];
            this.addProxyMethod(var8, var4);
        }
    }

    Iterator var11 = this.proxyMethods.values().iterator();

    List var12;
    while(var11.hasNext()) {
        var12 = (List)var11.next();
        checkReturnTypes(var12);
    }

    Iterator var15;
    try {
        // 生成代理类的构造函数
        this.methods.add(this.generateConstructor());
        var11 = this.proxyMethods.values().iterator();

        while(var11.hasNext()) {
            var12 = (List)var11.next();
            var15 = var12.iterator();

            while(var15.hasNext()) {
                ProxyGenerator.ProxyMethod var16 = (ProxyGenerator.ProxyMethod)var15.next();
                this.fields.add(new ProxyGenerator.FieldInfo(var16.methodFieldName, "Ljava/lang/reflect/Method;", 10));
                this.methods.add(var16.generateMethod());
            }
        }

        this.methods.add(this.generateStaticInitializer());
    } catch (IOException var10) {
        throw new InternalError("unexpected I/O Exception", var10);
    }

    if (this.methods.size() > 65535) {
        throw new IllegalArgumentException("method limit exceeded");
    } else if (this.fields.size() > 65535) {
        throw new IllegalArgumentException("field limit exceeded");
    } else {
        // 编写最终类文件
        this.cp.getClass(dotToSlash(this.className));
        this.cp.getClass("java/lang/reflect/Proxy");
        var1 = this.interfaces;
        var2 = var1.length;

        for(var3 = 0; var3 < var2; ++var3) {
            var4 = var1[var3];
            this.cp.getClass(dotToSlash(var4.getName()));
        }

        this.cp.setReadOnly();
        ByteArrayOutputStream var13 = new ByteArrayOutputStream();
        DataOutputStream var14 = new DataOutputStream(var13);

        try {
            var14.writeInt(-889275714);
            var14.writeShort(0);
            var14.writeShort(49);
            this.cp.write(var14);
            var14.writeShort(this.accessFlags);
            var14.writeShort(this.cp.getClass(dotToSlash(this.className)));
            var14.writeShort(this.cp.getClass("java/lang/reflect/Proxy"));
            var14.writeShort(this.interfaces.length);
            Class[] var17 = this.interfaces;
            int var18 = var17.length;

            for(int var19 = 0; var19 < var18; ++var19) {
                Class var22 = var17[var19];
                var14.writeShort(this.cp.getClass(dotToSlash(var22.getName())));
            }

            var14.writeShort(this.fields.size());
            var15 = this.fields.iterator();

            while(var15.hasNext()) {
                ProxyGenerator.FieldInfo var20 = (ProxyGenerator.FieldInfo)var15.next();
                var20.write(var14);
            }

            var14.writeShort(this.methods.size());
            var15 = this.methods.iterator();

            while(var15.hasNext()) {
                ProxyGenerator.MethodInfo var21 = (ProxyGenerator.MethodInfo)var15.next();
                var21.write(var14);
            }

            var14.writeShort(0);
            return var13.toByteArray();
        } catch (IOException var9) {
            throw new InternalError("unexpected I/O Exception", var9);
        }
    }
}

可以看到主要做了3件事:

  • 为所有方法生成代理调度代码,将代理方法对象集合起来
  • 为类中的方法生成字段信息和方法信息
  • 编写最终类

生成的代理类class文件为$Proxy0.class.通过对其反编译得到其源码如下:

package com.sun.proxy;

import com.test.Fruit;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy0 extends Proxy implements Fruit {
    // 保存Method对象,其中m3对应我们的eat方法,其余三个为hashCode、equals、toString方法
    private static Method m1;
    private static Method m3;
    private static Method m2;
    private static Method m0;

    // 代理类的构造函数
    // Proxy.newInstance方法就是通过通过这个构造函数来创建代理实例的
    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }

    // hashCode、equals、toString方法
    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 void eat() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    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 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"));
            m3 = Class.forName("com.test.Fruit").getMethod("eat");
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

可以看到以下特点:

  •  该类继承了Proxy实现了Fruit接口
  • 该类在static代码块中定义了所有该类包含的方法的Method实例,其中m3即通过反射获取的Fruit接口中的方法
  • 该类有一个构造器$Proxy0(InvocationHandler var1)传入调用处理器
  • 该类所有方法都将执行super.h.invoke并返回其结果,就是调用AppleProxy类中invoke方法。

至此JDK动态代理结束

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值