# 什么是反射机制

运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法。对于任意一个对象,都能够调用它的任意属性和方法。动态获取java类信息,以及动态调用对象方法的功能,便是反射机制。

# 反射机制

# 反射机制的相关类及抽象

  • 类,Lang包
public final class Class<T> implements java.io.Serializable,
                              GenericDeclaration,
                              Type,
                              AnnotatedElement {
    //创建类实例
    @CallerSensitive
    public T newInstance()
            throws InstantiationException, IllegalAccessException;
    //获取包名
    public Package getPackage();
   
    //获取类属性
    public Field[] getDeclaredFields() throws SecurityException ;

    //获取类方法
    @CallerSensitive
    public Method[] getDeclaredMethods() throws SecurityException;

    //获取构造器
    @CallerSensitive
    public Constructor<?>[] getDeclaredConstructors() throws SecurityException;
    
    //获取构造器
    public Annotation[] getDeclaredAnnotations();
    
    //是否是注解类
    boolean isAnnotation();
    
    //是否是匿名类
    boolean isAnonymousClass();

    //是否是接口
    boolean isInterface();

    //是否是内部类
    boolean isMemberClass();

    //省略其它抽象...
    }
  • 属性类Field,reflect包
public final
class Field extends AccessibleObject implements Member {

    //获取属性值
    @CallerSensitive
    public Object get(Object obj);

    //设置属性值
    @CallerSensitive
    public void set(Object obj, Object value)
            throws IllegalArgumentException, IllegalAccessException;

    //省略其它抽象...
}
  • 方法类Method,reflect包
public final class Method extends Executable {

    //动态执行方法
    @CallerSensitive
    public Object invoke(Object obj, Object... args)
            throws IllegalAccessException, IllegalArgumentException,
               InvocationTargetException;

    //省略其它抽象...
}
  • 构造器类Constructor,reflect包
public final class Constructor<T> extends Executable{
    //实例化对象
    @CallerSensitive
    public T newInstance(Object ... initargs)
            throws InstantiationException, IllegalAccessException,
                   IllegalArgumentException, InvocationTargetException;
    //省略其它抽象...
}

# 反射机制的优缺点

  • 优点: 动态加载类,提高灵活度
  • 缺点:
    1. 性能瓶颈
    2. 安全问题

# 代理模式

# 静态代理

  • 对目标对象的增强,通过手动完成;

# 动态代理

  • JDK动态代理
    • 组成:
      • Proxy: newProxyInstance对象
      • InvocationHandler: invoke方法,实现对目标对象的增强
    • 问题: 只能代理接口
  • CGLIB动态代理
    • 组成:
      • Enhancer: create方法
      • MethodInterceptor: intercept方法,实现对目标对象的增强

# JDK动态代理原理

  • 结论: 是动态创建代理类通过指定类加载器加载,然后在创建代理对象时将InvokerHandler对象作为构造参数传入
public class Proxy implements java.io.Serializable {

    //精简版的动态代理方法
    @CallerSensitive
    public static Object newProxyInstance(ClassLoader loader,
                                              Class<?>[] interfaces,
                                              InvocationHandler h)
            throws IllegalArgumentException
        {
            Objects.requireNonNull(h);
    
            final Class<?>[] intfs = interfaces.clone();
    
            Class<?> cl = getProxyClass0(loader, intfs);
    
            try {    
                final Constructor<?> cons = cl.getConstructor({ InvocationHandler.class });
                return cons.newInstance(new Object[]{h});
            } catch (Exception e) {
               //do nothing
            }
    }
    
    private static Class<?> getProxyClass0(ClassLoader loader,
                                               Class<?>... interfaces) {
            if (interfaces.length > 65535) {
                throw new IllegalArgumentException("interface limit exceeded");
            }
            return proxyClassCache.get(loader, interfaces);
    }
    
}

private static final class ProxyClassFactory
        implements BiFunction<ClassLoader, Class<?>[], Class<?>>
    {
        @Override
        public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
        
                    Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
                    for (Class<?> intf : interfaces) {
                        /*
                         * Verify that the class loader resolves the name of this
                         * interface to the same Class object.
                         */
                        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");
                        }
                        /*
                         * Verify that the Class object actually represents an
                         * interface.
                         */
                        if (!interfaceClass.isInterface()) {
                            throw new IllegalArgumentException(
                                interfaceClass.getName() + " is not an interface");
                        }
                        /*
                         * Verify that this interface is not a duplicate.
                         */
                        if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
                            throw new IllegalArgumentException(
                                "repeated interface: " + interfaceClass.getName());
                        }
                    }
        
                    String proxyPkg = null;     // package to define proxy class in
                    int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
        
                    /*
                     * Record the package of a non-public proxy interface so that the
                     * proxy class will be defined in the same package.  Verify that
                     * all non-public proxy interfaces are in the same package.
                     */
                    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) {
                        // if no non-public proxy interfaces, use com.sun.proxy package
                        proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
                    }
        
                    /*
                     * Choose a name for the proxy class to generate.
                     */
                    long num = nextUniqueNumber.getAndIncrement();
                    String proxyName = proxyPkg + "$Proxy" + num;
        
                    /*
                     * Generate the specified proxy class.
                     */
                    /*xxx: ProxyGenerator.generateProxyClass() 方法会按照指定 名称和接口集合生成代理类的字节
                           码,并根据条件决定是否保存到磁盘上*/
                    byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                        proxyName, interfaces, accessFlags);
                    try {
                        return defineClass0(loader, proxyName,
                                            proxyClassFile, 0, proxyClassFile.length);
                    } catch (ClassFormatError e) {
                        /*
                         * A ClassFormatError here means that (barring bugs in the
                         * proxy class generation code) there was some other
                         * invalid aspect of the arguments supplied to the proxy
                         * class creation (such as virtual machine limitations
                         * exceeded).
                         */
                        throw new IllegalArgumentException(e.toString());
                    }
        }
    }


public class ProxyGenerator {
    /*xxx: 生成字节码*/
    public static byte[] generateProxyClass(final String clazzName, Class<?>[] interfaces, int accessFlags) {
            ProxyGenerator generator = new ProxyGenerator(clazzName, interfaces, accessFlags);
            final byte[] bytecodes = generator.generateClassFile();
            if (saveGeneratedFiles) {
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        try {
                            int var1 = clazzName.lastIndexOf(46);
                            Path path;
                            if (var1 > 0) {
                                Path var3 = Paths.get(clazzName.substring(0, var1).replace('.', File.separatorChar));
                                Files.createDirectories(var3);
                                path = var3.resolve(clazzName.substring(var1 + 1, clazzName.length()) + ".class");
                            } else {
                                path = Paths.get(clazzName + ".class");
                            }
                            //根据条件,是否保存至文件中
                            Files.write(path, bytecodes, new OpenOption[0]);
                            return null;
                        } catch (IOException var4x) {
                            throw new InternalError("I/O exception saving generated file: " + var4x);
                        }
                    }
                });
            }
    
            return bytecodes;
    }

    private byte[] generateClassFile() {
            //省略....
            if (this.methods.size() > 65535) {
                throw new IllegalArgumentException("method limit exceeded");
            } else if (this.fields.size() > 65535) {
                throw new IllegalArgumentException("field limit exceeded");
            } else {
                this.cp.getClass(dotToSlash(this.className));
                this.cp.getClass("java/lang/reflect/Proxy");
                interfaceArray = this.interfaces;
                arrayLength = interfaceArray.length;
    
                for(index = 0; index < arrayLength; ++index) {
                    clazz = interfaceArray[index];
                    this.cp.getClass(dotToSlash(clazz.getName()));
                }
    
                this.cp.setReadOnly();
                ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream();
                DataOutputStream dataOutputStream = new DataOutputStream(arrayOutputStream);
    
                try {
                    dataOutputStream.writeInt(-889275714);
                    dataOutputStream.writeShort(0);
                    dataOutputStream.writeShort(49);
                    this.cp.write(dataOutputStream);
                    dataOutputStream.writeShort(this.accessFlags);
                    dataOutputStream.writeShort(this.cp.getClass(dotToSlash(this.className)));
                    dataOutputStream.writeShort(this.cp.getClass("java/lang/reflect/Proxy"));
                    dataOutputStream.writeShort(this.interfaces.length);
                    Class[] var17 = this.interfaces;
                    int var18 = var17.length;
    
                    for(int var19 = 0; var19 < var18; ++var19) {
                        Class var22 = var17[var19];
                        dataOutputStream.writeShort(this.cp.getClass(dotToSlash(var22.getName())));
                    }
    
                    dataOutputStream.writeShort(this.fields.size());
                    var15 = this.fields.iterator();
    
                    while(var15.hasNext()) {
                        ProxyGenerator.FieldInfo var20 = (ProxyGenerator.FieldInfo)var15.next();
                        var20.write(dataOutputStream);
                    }
    
                    dataOutputStream.writeShort(this.methods.size());
                    var15 = this.methods.iterator();
    
                    while(var15.hasNext()) {
                        ProxyGenerator.MethodInfo var21 = (ProxyGenerator.MethodInfo)var15.next();
                        var21.write(dataOutputStream);
                    }
    
                    dataOutputStream.writeShort(0);
                    /*xxx: 通过 DataOutputSteam 返回字节码*/
                    return arrayOutputStream.toByteArray();
                } catch (IOException var9) {
                    throw new InternalError("unexpected I/O Exception", var9);
                }
            }
    }
}
  • 一个反编译后的动态代理类:

interface CustomInterface{
 void doSomeThing();
}

public final class $Proxy1 extends Proxy implements CustomInterface{
    private static Method m3;

    static {
      m3 = Class.forName("xxx.xxx.CustomInterface").getMethod("doSomeThing",new Class[0]);
    }   

    public $Proxy1(InvocationHandler h) throws Exception{
        super(h);
    }

    public final void doSomeThing() throws Exception{
        super.h.invoke(this,m3,(Object[])null);
    }
}

# 反射注意事项

# getFields(),getMethods()反射的局限性

  • 只能获取public类型的属性,或者方法;

# getDeclaredFields(),getDeclaredMethods()

  • 既能获取到public类型的成员,又能获取private的成员
  • 对于private的成员,需要先设置 setAccessible