Java 反射机制(二)

前言

在上篇 Java 反射机制(一) 介绍了一些 Java 反射相关的经常使用 API ,在知道了如何去使用反射以后,做为一个合格的工程师,下一步确定是要去了解它的如何实现的,咱们今天就来看看在 JDK 源码中是如何去实现反射的(PS:如下源码分析基于 JDK1.8)。html

Field 类 set 方法的实现

Field 类的 set 方法是在运行时用来动态修改一个类的属性的值,进入到 Field 类的 set 方法的源码以下:java

public void set(Object obj, Object value) throws IllegalArgumentException, IllegalAccessException {
    if (!override) {
        if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
            Class<?> caller = Reflection.getCallerClass();
            checkAccess(caller, clazz, obj, modifiers);
        }
    }
    getFieldAccessor(obj).set(obj, value);
}
复制代码

首先根据 override 判断是否须要检查字段的访问权限,而后经过 getFieldAccessor 方法得到一个 FieldAccessor 字段访问者对象,最后调用的是 FieldAccessor 类的 set 方法进行下一步操做的,FieldAccessor 是一个接口,定义了对字段的一些操做,该接口有以下一些实现类:缓存

fieldaccessor_implements.png

要看 set 到底调用的是哪一个实现类的方法,那么咱们须要看看 getFieldAccessor() 返回的是哪一个类的对象,下面是 getFieldAccessor 方法的源码实现:安全

// security check is done before calling this method
private FieldAccessor getFieldAccessor(Object obj) throws IllegalAccessException {
    boolean ov = override;
    FieldAccessor a = (ov) ? overrideFieldAccessor : fieldAccessor;
    return (a != null) ? a : acquireFieldAccessor(ov);
}
复制代码

这里先经过 override 来获取不一样的缓存的 FieldAccessor,其中 overrideFieldAccessor 表明本类覆盖父类的字段访问者对象缓存,fieldAccessor 是本类的字段访问器对象缓存。若是缓存存在的话就直接复用以前的对象,不然就调用 Field 类的 acquireFieldAccessor 方法获取。咱们进入到 acquireFieldAccessor 方法中看看,方法源码以下:ide

private FieldAccessor acquireFieldAccessor(boolean overrideFinalCheck) {
    // First check to see if one has been created yet, and take it
    // if so
    FieldAccessor tmp = null;
    if (root != null) tmp = root.getFieldAccessor(overrideFinalCheck);
    if (tmp != null) {
        if (overrideFinalCheck)
            overrideFieldAccessor = tmp;
        else
            fieldAccessor = tmp;
    } else {
        // Otherwise fabricate one and propagate it up to the root
        tmp = reflectionFactory.newFieldAccessor(this, overrideFinalCheck);
        setFieldAccessor(tmp, overrideFinalCheck);
    }

    return tmp;
}
复制代码

acquireFieldAccessor 的源码中咱们能够看到,先判断是否已存在 FieldAccessor 对象,若是存在的话那么就会复用以前的 FieldAccessor 对象,不然就使用 reflectionFactory 工厂的 newFieldAccessor 方法生成一个新的 FieldAccessor 对象出来。因此咱们就要进到 newFieldAccessor 方法里面看看是如何生成的,方法源码以下:源码分析

public FieldAccessor newFieldAccessor(Field var1, boolean var2) {
    checkInitted();
    return UnsafeFieldAccessorFactory.newFieldAccessor(var1, var2);
}
复制代码

newFieldAccessor 方法代码能够得知,在方法里面是经过 UnsafeFieldAccessorFactory 类的 static 方法 newFieldAccessor 来生产 FieldAccessor 的,那么咱们继续进入到 UnsafeFieldAccessorFactory 类的 newFieldAccessor 方法里面看看,方法源码以下:post

static FieldAccessor newFieldAccessor(Field var0, boolean var1) {
    Class var2 = var0.getType();
    boolean var3 = Modifier.isStatic(var0.getModifiers());
    boolean var4 = Modifier.isFinal(var0.getModifiers());
    boolean var5 = Modifier.isVolatile(var0.getModifiers());
    boolean var6 = var4 || var5;
    boolean var7 = var4 && (var3 || !var1);
    if (var3) {
      UnsafeFieldAccessorImpl.unsafe.ensureClassInitialized(var0.getDeclaringClass());
      if (!var6) {
        if (var2 == Boolean.TYPE) {
          return new UnsafeStaticBooleanFieldAccessorImpl(var0);
        } else if (var2 == Byte.TYPE) {
          return new UnsafeStaticByteFieldAccessorImpl(var0);
        } else if (var2 == Short.TYPE) {
          return new UnsafeStaticShortFieldAccessorImpl(var0);
        } else if (var2 == Character.TYPE) {
          return new UnsafeStaticCharacterFieldAccessorImpl(var0);
        } else if (var2 == Integer.TYPE) {
          return new UnsafeStaticIntegerFieldAccessorImpl(var0);
        } else if (var2 == Long.TYPE) {
          return new UnsafeStaticLongFieldAccessorImpl(var0);
        } else if (var2 == Float.TYPE) {
          return new UnsafeStaticFloatFieldAccessorImpl(var0);
        } else {
          return (FieldAccessor)(var2 == Double.TYPE ? new UnsafeStaticDoubleFieldAccessorImpl(var0) : new UnsafeStaticObjectFieldAccessorImpl(var0));
        }
      }

      // 剩下的部分省略...

    }   
}       
复制代码

从以上 UnsafeFieldAccessorFactory 类的 newFieldAccessor 方法代码能够看出,方法里面经过类的字段修饰符类型和字段的类类型共同决定返回的 FieldAccessor 实现类,这里要注意一下方法里面这几个变量的含义:性能

  • var3(isStatic):静态属性,也就是 static 关键字修饰的属性。
  • var4(isFinal):final 关键字修饰的属性。
  • var5(isVolatile):valatile 关键字修饰的属性。
  • var6(isQualified):valatile 关键字或者 final 关键字修饰的属性。
  • var7 (isReadOnly):是否只读属性,final 关键字修饰的属性或者 static 关键字修饰而且不能覆盖(override = false)的属性

举一个例子,假设在一个类中的字段声明为 public static String name,那么返回的字段访问器为 UnsafeStaticCharacterFieldAccessorImpl,咱们看看这个类的 set 方法是如何实现的,方法源码以下:ui

public void set(Object var1, Object var2) throws IllegalArgumentException, IllegalAccessException {
    if (this.isFinal) {
      this.throwFinalFieldIllegalAccessException(var2);
    }

    if (var2 == null) {
      this.throwSetIllegalArgumentException(var2);
    }

    if (var2 instanceof Character) {
      unsafe.putChar(this.base, this.fieldOffset, (Character)var2);
    } else {
      this.throwSetIllegalArgumentException(var2);
    }
}
复制代码

从上面方法的代码得知,方法最终仍是经过 Unsafe 类的 native 方法 putChar(Object var1, long var2, char var4) 来实现的,有关 Unsafe 类的介绍请看这篇文章(Java魔法类:Unsafe应用解析)。this

Method 类 invoke 方法的实现

Method 类的 invoke 方法用来在运行时动态调用对象的方法,咱们进入到 Method 类的 invoke 方法中看看在 JDK 中究竟是怎么作的,方法源码以下:

public Object invoke(Object obj, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
    if (!override) {
        if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
            Class<?> caller = Reflection.getCallerClass();
            checkAccess(caller, clazz, obj, modifiers);
        }
    }
    MethodAccessor ma = methodAccessor;             // read volatile
    if (ma == null) {
        ma = acquireMethodAccessor();
    }
    return ma.invoke(obj, args);
}
复制代码

从以上方法代码咱们能够看到,和上文说的的 Field 类同样,首先也是先根据 override 进行了一些权限检查,最后调用的是 MethodAccessorinvoke 方法进行处理,这个方法访问器 MethodAccessor 是一个接口,它只有一个操做方法调用的 invoke 方法,它有以下三个实现类:

methodaccessor_implements.png

要想知道 ma.invoke 具体调用的是哪一个类的方法,咱们须要看看方法 acquireMethodAccessor 返回的对象是哪一个,该方法的源码以下:

private MethodAccessor acquireMethodAccessor() {
    // First check to see if one has been created yet, and take it
    // if so
    MethodAccessor tmp = null;
    if (root != null) tmp = root.getMethodAccessor();
    if (tmp != null) {
        methodAccessor = tmp;
    } else {
        // Otherwise fabricate one and propagate it up to the root
        tmp = reflectionFactory.newMethodAccessor(this);
        setMethodAccessor(tmp);
    }

    return tmp;
}
复制代码

从以上方法 acquireMethodAccessor 的源码能够看出,首先会先先判断是否已经存在了对应的 MethodAccessor 对象,若是有就会复用这个对象,不然就调用工厂 reflectionFactorynewMethodAccessor 方法生成一个 MethodAccessor 对象出来。那么咱们就须要进入到方法 newMethodAccessor 中,方法源码以下:

public MethodAccessor newMethodAccessor(Method var1) {
    checkInitted();
    if (noInflation && !ReflectUtil.isVMAnonymousClass(var1.getDeclaringClass())) {
      return (new MethodAccessorGenerator()).generateMethod(var1.getDeclaringClass(), var1.getName(), var1.getParameterTypes(), var1.getReturnType(), var1.getExceptionTypes(), var1.getModifiers());
    } else {
      NativeMethodAccessorImpl var2 = new NativeMethodAccessorImpl(var1);
      DelegatingMethodAccessorImpl var3 = new DelegatingMethodAccessorImpl(var2);
      var2.setParent(var3);
      return var3;
    }
}
复制代码

从方法 newMethodAccessor 的代码能够看到,方法首先是使用 Method 对象做为入参生成了 NativeMethodAccessorImpl 对象,而后再使用 NativeMethodAccessorImpl 对象做为入参生成了 DelegatingMethodAccessorImpl 对象。这个使用了代理模式,将 NativeMethodAccessorImpl 交给了 DelegatingMethodAccessorImpl 类进行了代理,进入到代理类 DelegatingMethodAccessorImpl 中能够看到:

delegatingmethodaccessorimpl.png

从上面的红色方框能够看到,在类 DelegatingMethodAccessorImpl 的构造方法中将参数赋值给类中的 delegate 属性,全部上所说的 ma.invoke 最终会进入到 DelegatingMethodAccessorImpl 代理类的 invoke,方法里调用的是 delegate 属性的 invoke 方法,该属性声明的类型为抽象类 MethodAccessorImpl,它有以下两个实现类:

methodaccessorimpl_implements.png

按照上文所说的,这里的 delegate 属性是 NativeMethodAccessorImpl 对象,那么就进入到 NativeMethodAccessorImplinvoke 方法中,方法源码以下:

public Object invoke(Object var1, Object[] var2) throws IllegalArgumentException, InvocationTargetException {
    if (++this.numInvocations > ReflectionFactory.inflationThreshold() && !ReflectUtil.isVMAnonymousClass(this.method.getDeclaringClass())) {
      MethodAccessorImpl var3 = (MethodAccessorImpl)(new MethodAccessorGenerator()).generateMethod(this.method.getDeclaringClass(), this.method.getName(), this.method.getParameterTypes(), this.method.getReturnType(), this.method.getExceptionTypes(), this.method.getModifiers());
      this.parent.setDelegate(var3);
    }

    return invoke0(this.method, var1, var2);
}
复制代码

NativeMethodAccessorImplinvoke 方法会先判断这次调用是否超过 ReflectionFactory.inflationThreshold() 方法返回的阈值(PS:默认的阈值大小为 15),若是超过了该阈值,则使用方法访问生成器从新生成一个 MethodAccessorImpl,并将 DelegatingMethodAccessorImpldelegate 属性指向这个新生成的 MethodAccessorImpl 对象。从 Reflectionfactory 工厂类的一下注释:

reflectionfactory_doc.png

能够得知 JVM 初次加载字节码实现反射的时候,使用 Method.invokeConstructor.newInstance 方式加载所花费的时间是使用原生代码加载所花费的时间的 3 - 4 倍。这也就是咱们日常说为何频繁使用反射的应用须要花费更多的时间。JVM 做者们为了不这种花费较长的加载时间,咱们在第一次加载的时候重用了 JVM 的入口,以后切换到字节码实现的实现。 正如注释所述,在 MethodAccessor 接口的实现中,有两个不一样的版本,一个 Java 实现的,一个是 Native 实现的。Java 版本实现的版本在初始化的时须要比较多的时间,但长久来讲性能会更好一些;而 Native 版本则正好相反,在初始化时相对较快,可是在运行一段时间以后性能就不如 Java 版本的了。为了权衡两种版本的特性,sun 公司的 JDK 使用了 inflation 机制,让 Java 方法在被反射调用时,开头的几回调用使用 native 版,等反射调用次数超过阈值时则生成一个专用的 MethodAccessor 实现类,生成其中的 invoke 方法的字节码,之后对该 Java 方法的反射调用就会使用 Java 版。

总结

本文主要介绍反射调用 set(Object obj, Object value) 方法和 invoke(Object obj, Object... args) 方法的底层实现,因为水平有限本人暂时尚未能力分析 JVM 的实现,这里只分析到最终 native 方法的调用。底层会依赖到 Unsafe 类来执行一些低级别、不安全操做的方法,如直接访问系统内存资源、自主管理内存资源等,这些方法在提高 Java 运行效率、加强 Java 语言底层资源操做能力方面起到了很大的做用。对于属性反射的方法 setXXXgetXXX 的实现分别对应 Unsafe 类的 putXXXgetXXX 方法,也就是说彻底依赖 Unsafe 类中的 native 方法来实现的;对于方法反射的方法 invoke 底层调用的是 NativeMethodAccessorImpl 类的 invoke0native 方法来实现的。对于反射构造器调用的实现,读者能够本身进入其源码进行分析,大致上和反射方法调用的实现相似。


参考文章

相关文章
相关标签/搜索