spring

JDK动态代理

2019-11-05  本文已影响0人  loveFXX

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字节码

上一篇下一篇

猜你喜欢

热点阅读