jdk代理

作者: 北海北_6dc3 | 来源:发表于2020-04-09 20:34 被阅读0次

使用示例

  • 定义接口
public interface Subject {
    void doSomething();
}
  • 定义实现
public class RealSubject implements Subject {
    @Override
    public void doSomething() {
        System.out.println("RealSubject do something");
    }
}
  • 定义jdk代理
public class JDKDynamicProxy implements InvocationHandler {

    private Object target;

    public JDKDynamicProxy(Object target) {
        this.target = target;
    }

    /**
     * 获取被代理接口实例对象
     * @param <T>
     * @return
     */
    public <T> T getProxy() {
        return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Do something before");
        Object result = method.invoke(target, args);
        System.out.println("Do something after");
        return result;
    }
}
  • 调用
public class Client {
    public static void main(String[] args) {
        // 保存生成的代理类的字节码文件
        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");

        // jdk动态代理测试
        Subject subject = new JDKDynamicProxy(new RealSubject()).getProxy();
        subject.doSomething();
    }
}

我们看到如果使用jdk代理,需要的核心要素有哪些?
1、接口及实现目标类
2、JDK代理类需要实现一个InvocationHandler 接口invoke方法。

这个实现,我们可以看出,是代理了类中所有方法。实现了相同的操作;
那么它的内部实现原理是什么?

原理

  • 生成代理对象
//核心实现,生成代理对象。
Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);

public class Proxy implements java.io.Serializable {
  public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        final Class<?>[] intfs = interfaces.clone();
、
        /*
         * 核心生成代理类
         */
        Class<?> cl = getProxyClass0(loader, intfs);

        /*
         *通过handler生成实例
         */
        final Constructor<?> cons = cl.getConstructor(constructorParams);
        return cons.newInstance(new Object[]{h});
    }
 }
  • 核心生成代理类,我们可以看到核心只需要相应接口和loader。
    private static Class<?> getProxyClass0(ClassLoader loader,
                                           Class<?>... interfaces) {
        return proxyClassCache.get(loader, interfaces);
    }

    // proxyClassCache.get
    public V get(K key, P parameter) {
        Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
        Factory factory = new Factory(key, parameter, subKey, valuesMap);
        return factory.get();
    }

        // factory.get
        public synchronized V get() {
             valueFactory.apply(key, parameter)
        }
//其中,valueFactory是构造函数中构造的。
public class Proxy {
    private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
        proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
}

final class WeakCache<K, P, V> {
    public WeakCache(BiFunction<K, P, ?> subKeyFactory,
                     BiFunction<K, P, V> valueFactory) {
        this.subKeyFactory = Objects.requireNonNull(subKeyFactory);
        this.valueFactory = Objects.requireNonNull(valueFactory);
    }
}
//所以valueFactory就是ProxyClassFactory
//继续查看applay方法

        // 所有代理类名称前缀为$Proxy
        private static final String proxyClassNamePrefix = "$Proxy";
        // 全局自增编号,和proxyClassNamePrefix 进行拼接,组成代理类名
        private static final AtomicLong nextUniqueNumber = new AtomicLong();
        public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
            //接口校验....
            String proxyPkg = null;     // package to define proxy class in
            int accessFlags = Modifier.PUBLIC | Modifier.FINAL;

            /*
             * 非public接口,代理类的包名与接口的包名相同
             */
            for (Class<?> intf : interfaces) {
                 ..
            }

            if (proxyPkg == null) {
                // if no non-public proxy interfaces, use com.sun.proxy package
                proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
            }
            /*
             *生成代理类名
             */
            long num = nextUniqueNumber.getAndIncrement();
            String proxyName = proxyPkg + proxyClassNamePrefix + num;
            /*
             * 生成代理类字节码。核心!!!!!
             */
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces, accessFlags);
        }
  • 代理类字节码生成。这个是核心类。
    这个类的命名空间package sun.misc,是个jdk提供的功能类
public class ProxyGenerator {
    public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) {
        ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
        final byte[] var4 = var3.generateClassFile();
  // 是否要将生成代理类的字节码文件保存到磁盘中
        if (saveGeneratedFiles) {
            // ....
        }
    }

    //new ProxyGenerator(var0, var1, var2);
    private ProxyGenerator(String var1, Class<?>[] var2, int var3) {
        this.className = var1;
        this.interfaces = var2;
        this.accessFlags = var3;
    }
   //var3.generateClassFile();核心中的核心。
    private byte[] generateClassFile() {
        //添加了三个方法。这三个方法怎么来的。看下面。
        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();
        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());
        } 
    }

   //generateClassFile中的三个添加方法
    private static Method hashCodeMethod;
    private static Method equalsMethod;
    private static Method toStringMethod;
    static {
        try {
            hashCodeMethod = Object.class.getMethod("hashCode", new Class[0]);
            equalsMethod = Object.class.getMethod("equals", new Class[]{Object.class});
            toStringMethod = Object.class.getMethod("toString", new Class[0]);
        } catch (NoSuchMethodException var1) {
            throw new NoSuchMethodError(var1.getMessage());
        }
    }


        private ProxyGenerator.MethodInfo generateMethod() throws IOException {
            DataOutputStream var9 = new DataOutputStream(var2.code);
            ProxyGenerator.this.code_aload(0, var9);
            var9.writeByte(180);
            var9.writeShort(ProxyGenerator.this.cp.getFieldRef("java/lang/reflect/Proxy", "h", "Ljava/lang/reflect/InvocationHandler;"));
            ProxyGenerator.this.code_aload(0, var9);
            var9.writeByte(178);
            var9.writeShort(ProxyGenerator.this.cp.getFieldRef(ProxyGenerator.dotToSlash(ProxyGenerator.this.className), this.methodFieldName, "Ljava/lang/reflect/Method;"));
            if(this.parameterTypes.length > 0) {
                ProxyGenerator.this.code_ipush(this.parameterTypes.length, var9);
                var9.writeByte(189);
                var9.writeShort(ProxyGenerator.this.cp.getClass("java/lang/Object"));

                for(int var10 = 0; var10 < this.parameterTypes.length; ++var10) {
                    var9.writeByte(89);
                    ProxyGenerator.this.code_ipush(var10, var9);
                    this.codeWrapArgument(this.parameterTypes[var10], var3[var10], var9);
                    var9.writeByte(83);
                }
            } else {
                var9.writeByte(1);
            }

            var9.writeByte(185);
           // ...字节流写入操作
        }

}
  • 生成的代理类
    在测试案例中,设置系统属性sun.misc.ProxyGenerator.saveGeneratedFiles值为true
 // 保存生成的代理类的字节码文件
 System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");

判定是否保存

public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) {
        ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
        final byte[] var4 = var3.generateClassFile();
        // 是否要将生成代理类的字节码文件保存到磁盘中
        if (saveGeneratedFiles) {
            // ....
        }
        return var4;
    }

打开$Proxy0.class文件如下:

package com.sun.proxy;

import com.example.aop.jdk.Subject;
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 Subject {
    private static Method m1;
    private static Method m4;
    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})).booleanValue();
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final void doSomething() throws  {
        try {
            super.h.invoke(this, m4, (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 void doSomething1() 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)).intValue();
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});
            m4 = Class.forName("com.example.aop.jdk.Subject").getMethod("doSomething", new Class[0]);
            m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
            m3 = Class.forName("com.example.aop.jdk.Subject").getMethod("doSomething1", new Class[0]);
            m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

1、继承了Proxy类,实现了代理的接口,由于java不能多继承,这里已经继承了Proxy类了,不能再继承其他的类,所以JDK的动态代理不支持对实现类的代理,只支持接口的代理。
2、提供了一个使用InvocationHandler作为参数的构造方法,最终所有方法都是调用此方法。并把真实对象方法传递进来,通过反射调用。
参考资料:
JDK动态代理实现原理

相关文章

网友评论

      本文标题:jdk代理

      本文链接:https://www.haomeiwen.com/subject/wlsqmhtx.html