美文网首页spring
JDK动态代理

JDK动态代理

作者: loveFXX | 来源:发表于2019-11-05 11:42 被阅读0次

    JDK动态代理是基于接口使用,通过Proxy.newProxyInstance方法使用。
    传入参数:当前类加载器、目标接口、带目标类的InvocationHandle实现类

    示例代码

    package com.jdklib;
    import org.springframework.stereotype.Component;
    @Component
    public class UserDaoImpl implements UserDao {
        @Override
        public void query() {
            System.out.println("UserDaoImpl");
        }
    }
    
    
    package com.jdklib;
    import org.springframework.stereotype.Component;
    @Component
    public interface UserDao {
        public void query();
    }
    
    
    package com.jdklib;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    public class MyInvocationHandle implements InvocationHandler {
        Object target;
        public MyInvocationHandle(Object target){
                this.target = target;
        }
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("proxy");
            return method.invoke( target,args );
        }
    }
    
    
    
    package com.jdklib;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.EnableAspectJAutoProxy;
    import sun.misc.ProxyGenerator;
    import java.io.FileOutputStream;
    import java.lang.reflect.Proxy;
    @Configuration
    @ComponentScan("com.jdklib")
    @EnableAspectJAutoProxy
    public class AppConfig {
        public static void main(String[] args) throws Exception {
            AnnotationConfigApplicationContext annotationConfigApplicationContext =
                    new AnnotationConfigApplicationContext( AppConfig.class );
            for (int i = 1; i < 20; i++) {
                UserDao userDao = (UserDao) Proxy.newProxyInstance( AppConfig.class.getClassLoader(), new Class[]{UserDao.class}, new MyInvocationHandle(new UserDaoImpl()) );
                userDao.query();
            }
            userDao.query();
            byte[] bytes= ProxyGenerator.generateProxyClass("$proxy",new Class[]{UserDao.class}  );
            FileOutputStream fileOutputStream = new FileOutputStream( "c://$proxy.class" );
            fileOutputStream.write( bytes );
            fileOutputStream.close();
        }
    }
    

    生成的代理类

    import com.jdklib1.UserDao;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.lang.reflect.UndeclaredThrowableException;
    
    public final class $proxy extends Proxy implements UserDao {
        private static Method m1;
        private static Method m3;
        private static Method m2;
        private static Method m0;
    
        public $proxy(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 void query() 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.jdklib1.UserDao").getMethod("query");
                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());
            }
        }
    }
    

    degub分析

    第一次调用链

    1、Proxy#newProxyInstance


    newProxyInstance.png

    2、Constructor#newInstance


    Constructor.png
    3、sun.reflect.DelegatingConstructorAccessorImpl#newInstance
    DelegatingConstructorAccessorImpl-newInstance.png

    4、sun.reflect.NativeConstructorAccessorImpl#newInstance


    NativeConstructorAccessorImpl-newInstance.png
    5、native的newInstance0
    private static native Object newInstance0(Constructor<?> var0, Object[] var1) throws InstantiationException, IllegalArgumentException, InvocationTargetException;
    

    第16次调用链

    4、sun.reflect.NativeConstructorAccessorImpl#newInstance


    NativeConstructorAccessorImplnewInstance16.png

    ReflectionFactory.inflationThreshold 默认值是15
    5、native的newInstance0

    第17次调用链

    3、sun.reflect.DelegatingConstructorAccessorImpl#newInstance


    GeneratedConstructorAccessor17.png

    4、执行GeneratedConstructorAccessor3代理类方法
    第16次调用generate方法生成代理类GeneratesConstructorAccessor,第17次执行GeneratesConstructorAccessor代理类方法


    asm.png

    Inflation机制

    反射类加载器会导致Perm溢出

    Constructor
    package sun.reflect;
    import java.lang.reflect.InvocationTargetException;
    public interface ConstructorAccessor {
        Object newInstance(Object[] var1) throws InstantiationException, IllegalArgumentException, InvocationTargetException;
    }
    

    ConstructorAccessor 有下面实现类
    1、NativeConstructorAccessorImpl
    JNI(java本地接口)
    2、DelegatingConstructorAccessorImpl
    注入ConstructorAccessorImpl属性(值是1或3),实现newInstance
    3、GeneratedConstructorAccessorX
    通过代理类

    Method
    package sun.reflect;
    import java.lang.reflect.InvocationTargetException;
    public interface MethodAccessor {
        Object invoke(Object var1, Object[] var2) throws IllegalArgumentException, InvocationTargetException;
    }
    

    MethodAccessor 有下面实现类
    1、NativeMethodAccessorImpl
    NativeMethodAccessorImpl是通过JNI(java本地接口)存取器获取反射类字节码信息
    2、DelegatingMethodAccessorImpl
    DelegatingMethodAccessorImpl注入MethodAccessorImpl属性(值是1或3),实现invoke调用
    3、GeneratedMethodAccessorX
    通过代理类加载反射类字节码

    numInvocations字段

    NativeConstructorAccessorImpl或NativeMethodAccessorImpl都有一个字段numInvocations。用来计算调用JNI次数
    当大于15就会生成GeneratedConstructorAccessorX或GeneratedConstructorAccessorX的字节码类文件,该字节码通过DelegatingClassLoader类加载。
    为什么设计这种机制:为了提高效率

    generate方法

    MethodAccessorGenerator类

    class MethodAccessorGenerator extends AccessorGenerator {
    public MethodAccessor generateMethod(Class<?> var1, String var2, Class<?>[] var3, Class<?> var4, Class<?>[] var5, int var6) {
            return (MethodAccessor)this.generate(var1, var2, var3, var4, var5, var6, false, false, (Class)null);
        }
    
        public ConstructorAccessor generateConstructor(Class<?> var1, Class<?>[] var2, Class<?>[] var3, int var4) {
            return (ConstructorAccessor)this.generate(var1, "<init>", var2, Void.TYPE, var3, var4, true, false, (Class)null);
        }
    
        public SerializationConstructorAccessorImpl generateSerializationConstructor(Class<?> var1, Class<?>[] var2, Class<?>[] var3, int var4, Class<?> var5) {
            return (SerializationConstructorAccessorImpl)this.generate(var1, "<init>", var2, Void.TYPE, var3, var4, true, true, var5);
        }
    
    private MagicAccessorImpl generate(final Class<?> var1, String var2, Class<?>[] var3, Class<?> var4, Class<?>[] var5, int var6, boolean var7, boolean var8, Class<?> var9) {
            ByteVector var10 = ByteVectorFactory.create();
            this.asm = new ClassFileAssembler(var10);
            this.declaringClass = var1;
            this.parameterTypes = var3;
            this.returnType = var4;
            this.modifiers = var6;
            this.isConstructor = var7;
            this.forSerialization = var8;
            this.asm.emitMagicAndVersion();
            short var11 = 42;
            boolean var12 = this.usesPrimitiveTypes();
            if (var12) {
                var11 = (short)(var11 + 72);
            }
    
            if (var8) {
                var11 = (short)(var11 + 2);
            }
    
            var11 += (short)(2 * this.numNonPrimitiveParameterTypes());
            this.asm.emitShort(add(var11, (short)1));
            final String var13 = generateName(var7, var8);
            this.asm.emitConstantPoolUTF8(var13);
            this.asm.emitConstantPoolClass(this.asm.cpi());
            this.thisClass = this.asm.cpi();
            if (var7) {
                if (var8) {
                    this.asm.emitConstantPoolUTF8("sun/reflect/SerializationConstructorAccessorImpl");
                } else {
                    this.asm.emitConstantPoolUTF8("sun/reflect/ConstructorAccessorImpl");
                }
            } else {
                this.asm.emitConstantPoolUTF8("sun/reflect/MethodAccessorImpl");
            }
    
            this.asm.emitConstantPoolClass(this.asm.cpi());
            this.superClass = this.asm.cpi();
            this.asm.emitConstantPoolUTF8(getClassName(var1, false));
            this.asm.emitConstantPoolClass(this.asm.cpi());
            this.targetClass = this.asm.cpi();
            short var14 = 0;
            if (var8) {
                this.asm.emitConstantPoolUTF8(getClassName(var9, false));
                this.asm.emitConstantPoolClass(this.asm.cpi());
                var14 = this.asm.cpi();
            }
    
            this.asm.emitConstantPoolUTF8(var2);
            this.asm.emitConstantPoolUTF8(this.buildInternalSignature());
            this.asm.emitConstantPoolNameAndType(sub(this.asm.cpi(), (short)1), this.asm.cpi());
            if (this.isInterface()) {
                this.asm.emitConstantPoolInterfaceMethodref(this.targetClass, this.asm.cpi());
            } else if (var8) {
                this.asm.emitConstantPoolMethodref(var14, this.asm.cpi());
            } else {
                this.asm.emitConstantPoolMethodref(this.targetClass, this.asm.cpi());
            }
    
            this.targetMethodRef = this.asm.cpi();
            if (var7) {
                this.asm.emitConstantPoolUTF8("newInstance");
            } else {
                this.asm.emitConstantPoolUTF8("invoke");
            }
    
            this.invokeIdx = this.asm.cpi();
            if (var7) {
                this.asm.emitConstantPoolUTF8("([Ljava/lang/Object;)Ljava/lang/Object;");
            } else {
                this.asm.emitConstantPoolUTF8("(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;");
            }
    
            this.invokeDescriptorIdx = this.asm.cpi();
            this.nonPrimitiveParametersBaseIdx = add(this.asm.cpi(), (short)2);
    
            for(int var15 = 0; var15 < var3.length; ++var15) {
                Class var16 = var3[var15];
                if (!isPrimitive(var16)) {
                    this.asm.emitConstantPoolUTF8(getClassName(var16, false));
                    this.asm.emitConstantPoolClass(this.asm.cpi());
                }
            }
    
            this.emitCommonConstantPoolEntries();
            if (var12) {
                this.emitBoxingContantPoolEntries();
            }
    
            if (this.asm.cpi() != var11) {
                throw new InternalError("Adjust this code (cpi = " + this.asm.cpi() + ", numCPEntries = " + var11 + ")");
            } else {
                this.asm.emitShort((short)1);
                this.asm.emitShort(this.thisClass);
                this.asm.emitShort(this.superClass);
                this.asm.emitShort((short)0);
                this.asm.emitShort((short)0);
                this.asm.emitShort((short)2);
                this.emitConstructor();
                this.emitInvoke();
                this.asm.emitShort((short)0);
                var10.trim();
                final byte[] var17 = var10.getData();
                return (MagicAccessorImpl)AccessController.doPrivileged(new PrivilegedAction<MagicAccessorImpl>() {
                    public MagicAccessorImpl run() {
                        try {
                            return (MagicAccessorImpl)ClassDefiner.defineClass(var13, var17, 0, var17.length, var1.getClassLoader()).newInstance();
                        } catch (IllegalAccessException | InstantiationException var2) {
                            throw new InternalError(var2);
                        }
                    }
                });
            }
        }
    
     private static synchronized String generateName(boolean var0, boolean var1) {
            int var2;
            if (var0) {
                if (var1) {
                    var2 = ++serializationConstructorSymnum;
                    return "sun/reflect/GeneratedSerializationConstructorAccessor" + var2;
                } else {
                    var2 = ++constructorSymnum;
                    return "sun/reflect/GeneratedConstructorAccessor" + var2;
                }
            } else {
                var2 = ++methodSymnum;
                return "sun/reflect/GeneratedMethodAccessor" + var2;
            }
        }
    }
    static Class<?> defineClass(String var0, byte[] var1, int var2, int var3, final ClassLoader var4) {
            ClassLoader var5 = (ClassLoader)AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
                public ClassLoader run() {
                    return new DelegatingClassLoader(var4);
                }
            });
            return unsafe.defineClass(var0, var1, var2, var3, var5, (ProtectionDomain)null);
        }
    

    generate方法实现了
    1、asm生成字节码数组
    2、defineClass生成DelegatingClassLoader代理类加载器
    3、generateName方法生成字节码文件GeneratedXXXAccessorX


    DelegatingClassLoader.png

    Inflation机制提高了反射的性能,但是对于重度使用有两个问题
    1、初次加载性能较低
    2、动态加载的字节码导致PermGen持续增长

    总结

    JDK是基于接口实现
    Inflation机制
    关键是生成代理类和调用inovke方法的实现方式
    1、JNI
    2、asm字节码

    相关文章

      网友评论

        本文标题:JDK动态代理

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