Skip to content

Latest commit

 

History

History
531 lines (465 loc) · 21.8 KB

动态代理.md

File metadata and controls

531 lines (465 loc) · 21.8 KB

动态代理

JDK 静态代理

HelloInterface ——> sayHello();
Hello implements HelloInterface ——> sayHello() {sout("Hello Eureka");}
public class HelloProxy implements HelloInterface {
    private HelloInterface hello = new Hello();
    @Override
    public sayHello() {
        sout("PRE PRE"); 
        hello.sayHello(); 
        sout("POST POST");
    }
}

JDK 动态代理(InvocationHandler)

HelloInterface ——> sayHello();
Hello implements HelloInterface ——> sayHello() {sout("Hello Eureka");}
public class HelloProxy implements InvocationHandler {
    private Object object;
    public HelloProxy (Object object) { 
        this.object = object; 
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("PRE PRE"); 
        method.invoke(object, args); 
        System.out.println("POST POST"); 
        return null;
    }
}
public class ProxyClient {
    public static void main(String[] args) {
        Hello hello = new Hello();
        InvocationHandler handler = new HelloProxy(hello);
        // 1
        HelloInterface proxy = (HelloInterface) Proxy.newProxyInstance(handler.getClass().getClassLoader(), hello.getClass().getInterfaces(), handler);
        // 2
        proxy.sayHello();
    }
}

​ 上边的 HelloInterface proxy 这个代理类(代码片段1),其实就是通过动态代理生成的 HelloInterface 接口的实现类,该实现类继承了 Proxy 这个类,核心代码如下(通过反编译生成的,实际代码还是比较多的):

//继承了Proxy类
public final class $Proxy extends Proxy implements HelloInterface {
    public $Proxy(InvocationHandler var1) throws  {
        super(var1);
    }
    public final void sayHello() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }
}

代码片段 2 执行会调用这个动态生成的代理实现类的 sayHello 方法。

类加载器是干嘛的
  • JDK 内部需要通过类加载器作为缓存的 key
  • 需要类加载器生成 class
为什么需要接口

​ 生成的代理类继承了 Proxy,由于 java 是单继承,所以只能实现接口,通过接口实现,充分利用了 java 的多态特性,也符合基于接口编码的规范

为什么 JDK 动态代理只能代理接口

​ 因为生成的代理类已经继承了 Proxy 类,Java 是单继承的,所以没法再继承另外一个类了。cglib 是通过操作字节码去完成代理的,其实JDK动态代理也操作了字节码。

JDK 静态代理与 JDK 动态代理比较

相同点:

都要创建代理类,以及代理类都要实现接口等。

不同点:
  • 在静态代理中我们需要对哪个接口和哪个被代理类创建代理类,所以我们在编译前就需要代理类实现与被代理类相同的接口,并且直接在实现的方法中调用被代理类相应的方法。
  • 但是动态代理则不同,我们不知道要针对哪个接口、哪个被代理类创建代理类,因为它是在运行时被创建的。
  • JDK 静态代理是通过直接编码创建的,JDK 动态代理是利用反射机制在运行时创建代理类的。

JDK 动态代理类生成是通过 Proxy 类中的 newProxyInstance 来完成的

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException {
    // 如果 h 为空将抛出异常
    Objects.requireNonNull(h);
    // 拷贝被代理类实现的一些接口,用于后面权限方面的一些检查
    final Class<?>[] intfs = interfaces.clone();
    final SecurityManager sm = System.getSecurityManager();
    if (sm != null) {
        // 在这里对某些安全权限进行检查,确保我们有权限对预期的被代理类进行代理
        checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
    }
    /*
     * 下面这个方法将产生代理类
     */
    Class<?> cl = getProxyClass0(loader, intfs);
    /*
     * 使用指定的调用处理程序获取代理类的构造函数对象
     */
    try {
        if (sm != null) {
            checkNewProxyPermission(Reflection.getCallerClass(), cl);
        }
        final Constructor<?> cons = cl.getConstructor(constructorParams);
        final InvocationHandler ih = h;
        // 假如代理类的构造函数是 private 的,就使用反射来 set accessible
        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);
    }
}
/**
 * 生成一个代理类,但是在调用本方法之前必须进行权限检查
 */
private static Class<?> getProxyClass0(ClassLoader loader, Class<?>... interfaces) {
    // 如果接口数量大于 65535,抛出非法参数错误
    if (interfaces.length > 65535) { 
        throw new IllegalArgumentException("interface limit exceeded"); 
    }
    // 如果在缓存中有对应的代理类,那么直接返回。
    // 否则代理类将由 ProxyClassFactory 来创建
    return proxyClassCache.get(loader, interfaces);
}
public V get(K key, P parameter) {
    Objects.requireNonNull(parameter);

    expungeStaleEntries();
    // 通过上游方法,可以知道 key 是类加载器,这里是通过类加载器可以获得第一层 key
   Object cacheKey = CacheKey.valueOf(key, refQueue);
    
   // 我们查看 map 的定义,可以看到 map 变量是一个两层的 ConcurrentMap
   // 通过第一层 key 尝试获取数据
   ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
   // 如果 valuesMap 为空,就新建一个 ConcurrentHashMap,
   // key 就是生成出来的 cacheKey,并把这个新建的 ConcurrentHashMap 推到 map
   if (valuesMap == null) {
        ConcurrentMap<Object, Supplier<V>> oldValuesMap
            = map.putIfAbsent(cacheKey,valuesMap = new ConcurrentHashMap<>());
        if (oldValuesMap != null) {
            valuesMap = oldValuesMap;
        }
    }

    // 通过上游方法可以知道 key 是类加载器,parameter 是类本身,
    // 这里是通过类加载器和类本身获得第二层 key
    Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
    Supplier<V> supplier = valuesMap.get(subKey);
    Factory factory = null;

    while (true) {
        if (supplier != null) {
            // 如果有缓存,直接调用 get 方法后返回,当没有缓存,会继续执行后面的代码,
            // 由于 while (true),会第二次跑到这里,再 get 返回出去,
            // 其中 get 方法调用的是 WeakCahce 中的静态内部类 Factory 的 get 方法
            V value = supplier.get();
            if (value != null) {
                return value;
            }
        }
        // 当 factory 为空,会创建 Factory 对象
        if (factory == null) {
            factory = new Factory(key, parameter, subKey, valuesMap);
        }

        if (supplier == null) {
            supplier = valuesMap.putIfAbsent(subKey, factory);
            if (supplier == null) {
                // 当没有代理类缓存的时候,会运行到这里,把 Factory 的对象赋值给 supplier ,
                //进行下一次循环,supplier 就不为空了,可以调用 get 方法返回出去了,
                //这个 Factory 位于 WeakCahce 类中,是一个静态内部类
                supplier = factory;
            }
        } else {
            if (valuesMap.replace(subKey, supplier, factory)) {
                supplier = factory;
            } else {
                supplier = valuesMap.get(subKey);
            }
        }
    }
}
/**
 *  里面有一个根据给定ClassLoader和Interface来创建代理类的工厂函数  
 *
 */
private static final class ProxyClassFactory implements BiFunction<ClassLoader, Class<?>[], Class<?>> {
    // 代理类的名字的前缀统一为“$Proxy”
    private static final String proxyClassNamePrefix = "$Proxy";

    // 每个代理类前缀后面都会跟着一个唯一的编号,如$Proxy0、$Proxy1、$Proxy2
    private static final AtomicLong nextUniqueNumber = new AtomicLong();

    @Override
    public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
        Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
        for (Class<?> intf : interfaces) {
            /*
             * 验证类加载器加载接口得到对象是否与由apply函数参数传入的对象相同
             */
            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");
            }
            /*
             * 验证这个Class对象是不是接口
             */
            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;     // 声明代理类所在的package
        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) {
            // 如果全是公共代理接口,那么生成的代理类就在com.sun.proxy package下
            proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
        }
        /*
         * 为代理类生成一个name  package name + 前缀+唯一编号
         * 如 com.sun.proxy.$Proxy0.class
         */
        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());
        }
    }
}
private byte[] generateClassFile() {
    //下面一系列的addProxyMethod方法是将接口中的方法和Object中的方法添加到代理方法中(proxyMethod)
    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);
    }

    //后面一系列的步骤用于写代理类Class文件
    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();
                //将代理类字段声明为Method,并且字段修饰符为 private static.
               //因为 10 是 ACC_PRIVATE和ACC_STATIC的与运算 故代理类的字段都是 private static Method ***
                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() > '\uffff') { //代理类中的方法数量超过65535就抛异常
        throw new IllegalArgumentException("method limit exceeded");
    } else if(this.fields.size() > '\uffff') {// 代理类中字段数量超过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);
        }
    }
}

private void addProxyMethod(Method var1, Class<?> var2) {
    String var3 = var1.getName();//获得方法名称
    Class[] var4 = var1.getParameterTypes();//获得方法参数类型
    Class var5 = var1.getReturnType();//获得方法返回类型
    Class[] var6 = var1.getExceptionTypes();//异常类型
    String var7 = var3 + getParameterDescriptors(var4);//获得方法签名
    Object var8 = (List)this.proxyMethods.get(var7);//根据方法前面获得proxyMethod的value
    if(var8 != null) {//处理多个代理接口中方法重复的情况
        Iterator var9 = ((List)var8).iterator();

        while(var9.hasNext()) {
            ProxyGenerator.ProxyMethod var10 = (ProxyGenerator.ProxyMethod)var9.next();
            if(var5 == var10.returnType) {
                ArrayList var11 = new ArrayList();
                collectCompatibleTypes(var6, var10.exceptionTypes, var11);
                collectCompatibleTypes(var10.exceptionTypes, var6, var11);
                var10.exceptionTypes = new Class[var11.size()];
                var10.exceptionTypes = (Class[])var11.toArray(var10.exceptionTypes);
                return;
            }
        }
    } else {
        var8 = new ArrayList(3);
        this.proxyMethods.put(var7, var8);
    }
    ((List)var8).add(new ProxyGenerator.ProxyMethod(var3, var4, var5, var6, var2, null));
}

CGLIB 原理剖析(MethodInterceptor、Enhancer)

基于 ASM 的字节码生成库,它允许我们在运行时对字节码进行修改和动态生成。ASM是一个轻量但高性能的字节码操作框架来转化字节码,产生新类。值得说的是,它比JDK动态代理还要快。

示例代码
/**
  * 被代理类
  */
public class HelloConcrete {
    public String sayHello(String str) {
        return "HelloConcrete: " + str;
    }
}

public class MyMethodInterceptor implements MethodInterceptor {
    
    public static Object getProxy(Class targetClass) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(targetClass);
        enhancer.setCallback(new MyMethodInterceptor());
        return enhancer.create();
    }
    
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("You said: " + Arrays.toString(args));
        return proxy.invokeSuper(obj, args);
    }
}

public static void main(String[] args) {
    HelloConcrete proxy = (HelloConcrete) MyMethodInterceptor.getProxy(HelloConcrete.class);
    System.out.println(proxy.sayHello("I love you!"));
}

​ 上述代码中,我们通过 CGLIB 的 Enhancer 来指定要代理的目标对象、实际处理代理逻辑的对象,最终通过调用 create() 方法得到代理对象,对这个对象所有非 final 方法的调用都会转发给 MethodInterceptor.intercept()方法,在 intercept() 方法里我们可以加入任何逻辑,比如修改方法参数,加入日志功能、安全检查功能等;通过调用 MethodProxy.invokeSuper() 方法,我们将调用转发给原始对象,具体到本例,就是 HelloConcrete 的具体方法。CGLIG 中 MethodInterceptor 的作用跟 JDK 代理中的 InvocationHandler 很类似,都是方法调用的中转站。

HelloConcrete 代理对象的类型信息
  • class=class cglib.HelloConcrete$$EnhancerByCGLIB$$e3734e52
  • superClass=class lh.HelloConcrete
  • interfaces=interface net.sf.cglib.proxy.Factory
  • invocationHandler=not java proxy class

​ CGLIB 代理之后的对象类型是 cglib.HelloConcrete$$EnhancerByCGLIB$$e3734e52,这是 CGLIB 动态生成的类型;父类是 HelloConcrete,印证了 CGLIB 是通过继承实现代理;同时实现了 net.sf.cglib.proxy.Factory 接口,这个接口是 CGLIB 自己加入的,包含一些工具方法。

​ 对于从 Object 中继承的方法,CGLIB 代理也会进行代理,如 hashCode()、equals()、toString()等,但是getClass()、wait()等方法不会,因为它是 final 方法,CGLIB 无法代理。

​ 既然是继承就不得不考虑 final 的问题。我们知道 final 类型不能有子类,所以 CGLIB 不能代理 final 类型。同样,只能代理非 final 修饰的非抽象类的非 final 方法

cglib.HelloConcrete$$EnhancerByCGLIB$$e3734e52 具体内容是:
public class HelloConcrete$$EnhancerByCGLIB$$e3734e52 extends HelloConcrete implements Factory {
  ...
  private MethodInterceptor CGLIB$CALLBACK_0; // ~~
  ...
  public final String sayHello(String paramString) {
    ...
    MethodInterceptor tmp17_14 = CGLIB$CALLBACK_0;
    if (tmp17_14 != null) {
      // 将请求转发给 MethodInterceptor.intercept() 方法
      return (String)tmp17_14.intercept(this, 
              CGLIB$sayHello$0$Method, 
              new Object[] { paramString }, 
              CGLIB$sayHello$0$Proxy);
    }
    return super.sayHello(paramString);
  }
  ...
}