Skip to content

Commit fc50bc7

Browse files
committed
Reflection: 完成
1 parent e7e34d0 commit fc50bc7

File tree

2 files changed

+204
-2
lines changed

2 files changed

+204
-2
lines changed

note/Reflection/Reflection.uml

+61-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
<XPD:OBJ name="OwnedElements[0]" type="UMLModel" guid="kailyBPKekuUixQ3X4Ac0wAA">
1414
<XPD:ATTR name="Name" type="string">classes</XPD:ATTR>
1515
<XPD:REF name="Namespace">OgMvQ//nPEa3ihAvljlC+wAA</XPD:REF>
16-
<XPD:ATTR name="#OwnedDiagrams" type="integer">1</XPD:ATTR>
16+
<XPD:ATTR name="#OwnedDiagrams" type="integer">2</XPD:ATTR>
1717
<XPD:OBJ name="OwnedDiagrams[0]" type="UMLClassDiagram" guid="/e3GRMridkSx10/d+pVdCQAA">
1818
<XPD:ATTR name="Name" type="string">Class</XPD:ATTR>
1919
<XPD:REF name="DiagramOwner">kailyBPKekuUixQ3X4Ac0wAA</XPD:REF>
@@ -218,7 +218,46 @@
218218
</XPD:OBJ>
219219
</XPD:OBJ>
220220
</XPD:OBJ>
221-
<XPD:ATTR name="#OwnedElements" type="integer">7</XPD:ATTR>
221+
<XPD:OBJ name="OwnedDiagrams[1]" type="UMLClassDiagram" guid="91FgC6xBOk6NrkAYsWCvygAA">
222+
<XPD:ATTR name="Name" type="string">ReflectionData</XPD:ATTR>
223+
<XPD:REF name="DiagramOwner">kailyBPKekuUixQ3X4Ac0wAA</XPD:REF>
224+
<XPD:OBJ name="DiagramView" type="UMLClassDiagramView" guid="h+pZ0KbweUeXV6wZz1yCsgAA">
225+
<XPD:REF name="Diagram">91FgC6xBOk6NrkAYsWCvygAA</XPD:REF>
226+
<XPD:ATTR name="#OwnedViews" type="integer">1</XPD:ATTR>
227+
<XPD:OBJ name="OwnedViews[0]" type="UMLClassView" guid="dOioqLAPyUKIQ41JBrhhawAA">
228+
<XPD:ATTR name="LineColor" type="string">clMaroon</XPD:ATTR>
229+
<XPD:ATTR name="FillColor" type="string">$00B9FFFF</XPD:ATTR>
230+
<XPD:ATTR name="Left" type="integer">320</XPD:ATTR>
231+
<XPD:ATTR name="Top" type="integer">88</XPD:ATTR>
232+
<XPD:ATTR name="Width" type="integer">148</XPD:ATTR>
233+
<XPD:ATTR name="Height" type="integer">69</XPD:ATTR>
234+
<XPD:REF name="Model">ph/mQc5fgUa/HumhAnmm3QAA</XPD:REF>
235+
<XPD:OBJ name="NameCompartment" type="UMLNameCompartmentView" guid="cMVbYc+RIUe1ej5EIYKrbwAA">
236+
<XPD:OBJ name="NameLabel" type="LabelView" guid="CYeSPGOPdkOHrfDcCxZgTAAA">
237+
<XPD:ATTR name="FontStyle" type="integer">1</XPD:ATTR>
238+
<XPD:ATTR name="Text" type="string">ReflectionData</XPD:ATTR>
239+
</XPD:OBJ>
240+
<XPD:OBJ name="StereotypeLabel" type="LabelView" guid="eaNpPCzDuEG2OmneU/wakQAA">
241+
<XPD:ATTR name="Visible" type="boolean">False</XPD:ATTR>
242+
</XPD:OBJ>
243+
<XPD:OBJ name="PropertyLabel" type="LabelView" guid="raZtcRMMh0WnGvFhRAFnvwAA">
244+
<XPD:ATTR name="Visible" type="boolean">False</XPD:ATTR>
245+
</XPD:OBJ>
246+
</XPD:OBJ>
247+
<XPD:OBJ name="AttributeCompartment" type="UMLAttributeCompartmentView" guid="1T+I3YDOiUavNlfNCxsOhgAA">
248+
<XPD:REF name="Model">ph/mQc5fgUa/HumhAnmm3QAA</XPD:REF>
249+
</XPD:OBJ>
250+
<XPD:OBJ name="OperationCompartment" type="UMLOperationCompartmentView" guid="hjv0YGumCkG+ZYibjna5YQAA">
251+
<XPD:REF name="Model">ph/mQc5fgUa/HumhAnmm3QAA</XPD:REF>
252+
</XPD:OBJ>
253+
<XPD:OBJ name="TemplateParameterCompartment" type="UMLTemplateParameterCompartmentView" guid="JNaewO1y2Ee6W7T0eH/qLgAA">
254+
<XPD:ATTR name="Visible" type="boolean">False</XPD:ATTR>
255+
<XPD:REF name="Model">ph/mQc5fgUa/HumhAnmm3QAA</XPD:REF>
256+
</XPD:OBJ>
257+
</XPD:OBJ>
258+
</XPD:OBJ>
259+
</XPD:OBJ>
260+
<XPD:ATTR name="#OwnedElements" type="integer">8</XPD:ATTR>
222261
<XPD:OBJ name="OwnedElements[0]" type="UMLInterface" guid="EjXqGPk9REiBDT5eizwq/AAA">
223262
<XPD:ATTR name="Name" type="string">AnnotatedElement</XPD:ATTR>
224263
<XPD:REF name="Namespace">kailyBPKekuUixQ3X4Ac0wAA</XPD:REF>
@@ -331,6 +370,26 @@
331370
<XPD:REF name="Views[2]">UxWkkEXHA02vaKrNmWg9EgAA</XPD:REF>
332371
<XPD:REF name="Views[3]">H3JoXI7xfUi2Pc5G63vjBAAA</XPD:REF>
333372
</XPD:OBJ>
373+
<XPD:OBJ name="OwnedElements[7]" type="UMLClass" guid="ph/mQc5fgUa/HumhAnmm3QAA">
374+
<XPD:ATTR name="Name" type="string">ReflectionData</XPD:ATTR>
375+
<XPD:REF name="Namespace">kailyBPKekuUixQ3X4Ac0wAA</XPD:REF>
376+
<XPD:ATTR name="#Views" type="integer">4</XPD:ATTR>
377+
<XPD:REF name="Views[0]">dOioqLAPyUKIQ41JBrhhawAA</XPD:REF>
378+
<XPD:REF name="Views[1]">1T+I3YDOiUavNlfNCxsOhgAA</XPD:REF>
379+
<XPD:REF name="Views[2]">hjv0YGumCkG+ZYibjna5YQAA</XPD:REF>
380+
<XPD:REF name="Views[3]">JNaewO1y2Ee6W7T0eH/qLgAA</XPD:REF>
381+
<XPD:ATTR name="#Attributes" type="integer">2</XPD:ATTR>
382+
<XPD:OBJ name="Attributes[0]" type="UMLAttribute" guid="x7LE0cmMaUmWCNxCpPnR0AAA">
383+
<XPD:ATTR name="Name" type="string">volatile Field declaredFields</XPD:ATTR>
384+
<XPD:ATTR name="Visibility" type="UMLVisibilityKind">vkPackage</XPD:ATTR>
385+
<XPD:REF name="Owner">ph/mQc5fgUa/HumhAnmm3QAA</XPD:REF>
386+
</XPD:OBJ>
387+
<XPD:OBJ name="Attributes[1]" type="UMLAttribute" guid="81e3dYP9Q0mGMuskBff70AAA">
388+
<XPD:ATTR name="Name" type="string">volatile Field publicFields</XPD:ATTR>
389+
<XPD:ATTR name="Visibility" type="UMLVisibilityKind">vkPackage</XPD:ATTR>
390+
<XPD:REF name="Owner">ph/mQc5fgUa/HumhAnmm3QAA</XPD:REF>
391+
</XPD:OBJ>
392+
</XPD:OBJ>
334393
</XPD:OBJ>
335394
</XPD:OBJ>
336395
</XPD:BODY>

note/Reflection/reflection.md

+143
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,146 @@
44

55
# 方法获取
66

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

Comments
 (0)