|
4 | 4 |
|
5 | 5 | # 方法获取
|
6 | 6 |
|
| 7 | +我们以getDeclaredMethods为例: |
| 8 | + |
| 9 | +```java |
| 10 | +@CallerSensitive |
| 11 | +public Method[] getDeclaredMethods() throws SecurityException { |
| 12 | + return copyMethods(privateGetDeclaredMethods(false)); |
| 13 | +} |
| 14 | +``` |
| 15 | + |
| 16 | +privateGetDeclaredMethods: |
| 17 | + |
| 18 | +```java |
| 19 | +private Method[] privateGetDeclaredMethods(boolean publicOnly) { |
| 20 | + Method[] res; |
| 21 | + ReflectionData<T> rd = reflectionData(); |
| 22 | + if (rd != null) { |
| 23 | + res = publicOnly ? rd.declaredPublicMethods : rd.declaredMethods; |
| 24 | + if (res != null) return res; |
| 25 | + } |
| 26 | + // No cached value available; request value from VM |
| 27 | + res = Reflection.filterMethods(this, getDeclaredMethods0(publicOnly)); |
| 28 | + if (rd != null) { |
| 29 | + if (publicOnly) { |
| 30 | + rd.declaredPublicMethods = res; |
| 31 | + } else { |
| 32 | + rd.declaredMethods = res; |
| 33 | + } |
| 34 | + } |
| 35 | + return res; |
| 36 | +} |
| 37 | +``` |
| 38 | + |
| 39 | +publicOnly为false便说明需要获取各种访问级别的方法。 |
| 40 | + |
| 41 | +## 缓存 |
| 42 | + |
| 43 | +为加快方法获取的性能,这里会对反射的结果进行缓存。缓存以Class内部类ReflectionData对象的形式进行保存: |
| 44 | + |
| 45 | +```java |
| 46 | +private static class ReflectionData<T> { |
| 47 | + volatile Field[] declaredFields; |
| 48 | + volatile Field[] publicFields; |
| 49 | + volatile Method[] declaredMethods; |
| 50 | + volatile Method[] publicMethods; |
| 51 | + volatile Constructor<T>[] declaredConstructors; |
| 52 | + volatile Constructor<T>[] publicConstructors; |
| 53 | + // Intermediate results for getFields and getMethods |
| 54 | + volatile Field[] declaredPublicFields; |
| 55 | + volatile Method[] declaredPublicMethods; |
| 56 | + volatile Class<?>[] interfaces; |
| 57 | + // Value of classRedefinedCount when we created this ReflectionData instance |
| 58 | + final int redefinedCount; |
| 59 | + ReflectionData(int redefinedCount) { |
| 60 | + this.redefinedCount = redefinedCount; |
| 61 | + } |
| 62 | +} |
| 63 | +``` |
| 64 | + |
| 65 | +reflectionData方法: |
| 66 | + |
| 67 | +```java |
| 68 | +private ReflectionData<T> reflectionData() { |
| 69 | + SoftReference<ReflectionData<T>> reflectionData = this.reflectionData; |
| 70 | + int classRedefinedCount = this.classRedefinedCount; |
| 71 | + ReflectionData<T> rd; |
| 72 | + if (useCaches && reflectionData != null && (rd = reflectionData.get()) != null && |
| 73 | + rd.redefinedCount == classRedefinedCount) { |
| 74 | + return rd; |
| 75 | + } |
| 76 | + // else no SoftReference or cleared SoftReference or stale ReflectionData |
| 77 | + // -> create and replace new instance |
| 78 | + return newReflectionData(reflectionData, classRedefinedCount); |
| 79 | +} |
| 80 | +``` |
| 81 | + |
| 82 | +与之相关的两个属性定义: |
| 83 | + |
| 84 | +```java |
| 85 | +private volatile transient SoftReference<ReflectionData<T>> reflectionData; |
| 86 | +// Incremented by the VM on each call to JVM TI RedefineClasses() |
| 87 | +// that redefines this class or a superclass. |
| 88 | +private volatile transient int classRedefinedCount = 0; |
| 89 | +``` |
| 90 | + |
| 91 | +从这里可以看出,每次JVM对当前类或其父类重新加载时都会导致classRedefinedCount的增加。Class使用了软引用进行缓存,**只要虚拟机进行Full GC,便会对软引用指向的对象进行回收**,所以软引用的对象的生存周期是当前至下一次Full GC。 |
| 92 | + |
| 93 | +变量useCaches决定了是否对反射结果进行缓存,其取值由方法checkInitted决定,相关源码: |
| 94 | + |
| 95 | +```java |
| 96 | +String val = System.getProperty("sun.reflect.noCaches"); |
| 97 | +if (val != null && val.equals("true")) { |
| 98 | + useCaches = false; |
| 99 | +} |
| 100 | +``` |
| 101 | + |
| 102 | +有意思的细节: 这里使用字符串比较判断是否为true,而不是使用Boolean.getBoolean方法,这样是为了**避免Boolean类的初始化**,因为JVM规范定义了对类的静态方法的调用将导致类的初始化。 |
| 103 | + |
| 104 | +注意reflectionData方法判断缓存是否有效的条件里的这一个: |
| 105 | + |
| 106 | +```java |
| 107 | +rd.redefinedCount == classRedefinedCount |
| 108 | +``` |
| 109 | + |
| 110 | +这就是说,只有缓存保存的类加载次数与类保存的相一致时缓存才是有效的。 |
| 111 | + |
| 112 | +## 过滤 |
| 113 | + |
| 114 | +当没有缓存或缓存已失效或被回收时,便需要向JVM请求获得相关信息,这里是通过native方法getDeclaredMethods0实现,类Reflection位于sun.reflect包下,JDK这样解释其功能: 将敏感的或是JVM内部的对象(属性或方法)过滤出去。 |
| 115 | + |
| 116 | +## 拷贝 |
| 117 | + |
| 118 | +copyMethods实现: |
| 119 | + |
| 120 | +```java |
| 121 | +private static Method[] copyMethods(Method[] arg) { |
| 122 | + Method[] out = new Method[arg.length]; |
| 123 | + ReflectionFactory fact = getReflectionFactory(); |
| 124 | + for (int i = 0; i < arg.length; i++) { |
| 125 | + out[i] = fact.copyMethod(arg[i]); |
| 126 | + } |
| 127 | + return out; |
| 128 | +} |
| 129 | +``` |
| 130 | + |
| 131 | +跳过复杂的调用关系,真正进行拷贝的其实就是Method的copy方法: |
| 132 | + |
| 133 | +```java |
| 134 | +Method copy() { |
| 135 | + if (this.root != null) |
| 136 | + throw new IllegalArgumentException("Can not copy a non-root Method"); |
| 137 | + Method res = new Method(clazz, name, parameterTypes, returnType, |
| 138 | + exceptionTypes, modifiers, slot, signature, |
| 139 | + annotations, parameterAnnotations, annotationDefault); |
| 140 | + res.root = this; |
| 141 | + // Might as well eagerly propagate this if already present |
| 142 | + res.methodAccessor = methodAccessor; |
| 143 | + return res; |
| 144 | +} |
| 145 | +``` |
| 146 | + |
| 147 | +可以看出,每次返回的都是一个全新的Method对象,新对象的root属性指向原对象,一个Method对象及其副本共享一个methodAccessor,methodAccessor对象可以看做是对JVM相应方法的引用。 |
| 148 | + |
| 149 | +那这里为什么要进行拷贝呢? |
0 commit comments