JDK和CGLIB动态代理原理

JDK动态代理原理解析

一、例子:

1、定义基础接口
public interface HttpApi {
    String get(String url);
}
2、实现类
public class RealModule implements HttpApi {
     @Override
     public String get(String url) {
         return "result";
     }
}
3、动态代理
public class ProxyFactory {
    public static HttpApi getProxy(HttpApi target) {
        return (HttpApi) Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new LogHandler(target));
    }

    // 增强类
    private static class LogHandler implements InvocationHandler {
        private HttpApi target;

        LogHandler(HttpApi target) {
            this.target = target;
        }
        // method底层的方法无参数时,args为空或者长度为0
        @Override
        public Object invoke(Object proxy, Method method, @Nullable Object[] args)       
               throws Throwable {
            // 扩展的功能
            Log.i("http-statistic", (String) args[0]);
            // 访问基础对象
            return method.invoke(target, args);
        }
    }
}

上面例子中出现的核心方法有:

  • Proxy.newProxyInstance( target.getClass().getClassLoader(),target.getClass().getInterfaces(),new LogHandler(target));
  • 参数说明:1.类加载器。2.指定newProxyInstance()方法返回的对象要实现哪些接口,可以指定多个接口。3.调用处理器,实现了InvocationHandler接口的实现类,重写invoke方法来增强被代理类的方法。
  • 方法返回:实现了指定接口的实现类对象,即被代理类。
  • invoke(Object proxy, Method method, @Nullable Object[] args) ;
  • 参数说明:1.代理对象,也就是Proxy.newProxyInstance()方法返回的对象。2.被代理对象的方法如例子中的get()方法。3.表示当前被调用方法的参数。
  • 方法返回:前被调用的方法的返回值,没有返回值则返回null。

二、反编译代理类源码

public final class $proxy0 extends Proxy implements HttpApi {
    //反射的元数据Method存储起来,避免重复创建
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;

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

    /**
     * Object#hashCode()
     * Object#equals(Object)
     * Object#toString()
     */

    // 实现了HttpApi接口
    public final String get() throws  {
        try {
            //转发到Invocation#invoke()
            return (String)super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            //Object#hashCode()
            //Object#equals(Object)
            //Object#toString()
            m3 = Class.forName("HttpApi").getMethod("get");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

通过反编译的源码我们可以得到以下结论:

  • JDK动态代理生成了代理类(继承Proxy)的字节码文件(Class)。
  • 代理类继承自 java.lang.reflect.Proxy,实现了HttpApi接口。
  • 代理类中的所有方法都是final 的。
  • 代理类所有的方法功能的实现都统一调用了InvocationHandler的invoke()方法。
  • 通过(String)super.h.invoke(this, m3, (Object[])null)方法进入增强类以实现对被代理方法的增强。
  • JDK动态代理只能对实现了接口的类进行代理,不能对普通类进行代理,这是因为JDK动态代理生成的新的代理类其父类是Proxy,java不支持类的多继承,所以只能实现接口。

三、核心类Proxy源码解析

1.JDK动态代理核心类:Proxy。

2.Proxy主要API

方法 描述
getProxyClass(ClassLoader, Class<?>...) : Class<?> 获取实现目标接口的代理类 Class 对象
newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h): Object 获取实现目标接口的代理对象
isProxyClass(Class<?>) : boolean 判断一个 Class 对象是否属于代理类
getInvocationHandler(Object) : InvocationHandler 获取代理对象内部的 InvocationHandler

3.核心源码:

3.1 Proxy.java

1、获取代理类 Class 对象
public static Class<?> getProxyClass(ClassLoader loader,Class<?>... interfaces){
    final Class<?>[] intfs = interfaces.clone();
    ...
    1.1 获得代理类 Class 对象
    return getProxyClass0(loader, intfs);
}

2、实例化代理类对象
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h){
    ...
    final Class<?>[] intfs = interfaces.clone();
    2.1 获得代理类 Class对象
    Class<?> cl = getProxyClass0(loader, intfs);
    ...
    2.2 获得代理类构造器 (接收一个 InvocationHandler 参数)
    // private static final Class<?>[] constructorParams = { InvocationHandler.class };
    final Constructor<?> cons = cl.getConstructor(constructorParams);
    final InvocationHandler ih = h;
    ...
    2.3 反射创建实例
    return newInstance(cons, ih);
}

可以看到,实例化代理对象也需要先通过 getProxyClass0(...) 获取代理类 Class 对象&

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值