-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathspring-cglib-and-asm.drawio
272 lines (272 loc) · 99.9 KB
/
spring-cglib-and-asm.drawio
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
<mxfile host="Electron" modified="2024-11-03T08:36:17.883Z" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/21.6.5 Chrome/114.0.5735.243 Electron/25.3.1 Safari/537.36" etag="uxTZ1cgjiutveAd0507l" version="21.6.5" type="device">
<diagram name="第 1 页" id="Au8LBIZ9-3zIQxEieEoI">
<mxGraphModel dx="3935" dy="879" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
<mxCell id="VISHqFL7TcA8I7J5W86J-1" value="<h1 style=""><font style="font-size: 16px;">Spring CgLib + ASM 工作原理</font><font style="font-size: 12px; font-weight: normal;">(spring-core:5.3.27)</font></h1><div><font style="font-size: 12px; font-weight: normal;">Spring 实现 AOP 动态代理没有引入 CgLib 库,而是将 CgLib 库部分源码打包到了 spring-core,由于 CgLib 依赖 ASM,Spring 也将依赖的 ASM 部门源码打包到了 spring-core。</font></div><div><font style="font-size: 12px; font-weight: normal;">由于只是打包了部分代码 org.springframework.asm&nbsp;org.springframework.cglib 下的代码比 ASM Cglib 框架源码要少。</font></div><div>细节太多了,先暂停下,TODO</div><div><b>基础:</b></div><div>1. Java 字节码文件结构</div><p></p>" style="text;html=1;strokeColor=none;fillColor=none;spacing=5;spacingTop=-20;whiteSpace=wrap;overflow=hidden;rounded=0;" parent="1" vertex="1">
<mxGeometry x="40" y="10" width="760" height="140" as="geometry" />
</mxCell>
<mxCell id="VISHqFL7TcA8I7J5W86J-6" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;fontSize=11;" parent="1" source="VISHqFL7TcA8I7J5W86J-2" target="VISHqFL7TcA8I7J5W86J-5" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="VISHqFL7TcA8I7J5W86J-2" value="DefaultGeneratorStrategy#generate(<br style="font-size: 11px;">ClassGenerator cg)" style="rounded=1;whiteSpace=wrap;html=1;fontSize=11;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" vertex="1">
<mxGeometry x="40" y="170" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="VISHqFL7TcA8I7J5W86J-3" value="<font color="#007fff" style="">Spring CgLib 借助 GeneratorStrategy<br>#generate()生成代理类的字节码<br>比如:DefaultGeneratorStrategy<br></font>" style="text;html=1;align=left;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontSize=11;" parent="1" vertex="1">
<mxGeometry x="40" y="235" width="210" height="50" as="geometry" />
</mxCell>
<mxCell id="VISHqFL7TcA8I7J5W86J-8" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;fontSize=11;" parent="1" source="VISHqFL7TcA8I7J5W86J-5" target="VISHqFL7TcA8I7J5W86J-7" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="VISHqFL7TcA8I7J5W86J-9" value="1" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];fontSize=11;" parent="VISHqFL7TcA8I7J5W86J-8" vertex="1" connectable="0">
<mxGeometry x="0.15" y="-2" relative="1" as="geometry">
<mxPoint x="8" y="-1" as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="VISHqFL7TcA8I7J5W86J-13" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="VISHqFL7TcA8I7J5W86J-5" target="VISHqFL7TcA8I7J5W86J-10" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="VISHqFL7TcA8I7J5W86J-15" value="2" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="VISHqFL7TcA8I7J5W86J-13" vertex="1" connectable="0">
<mxGeometry x="0.8143" y="-1" relative="1" as="geometry">
<mxPoint as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="VISHqFL7TcA8I7J5W86J-14" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="VISHqFL7TcA8I7J5W86J-5" target="VISHqFL7TcA8I7J5W86J-12" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="VISHqFL7TcA8I7J5W86J-16" value="3" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="VISHqFL7TcA8I7J5W86J-14" vertex="1" connectable="0">
<mxGeometry x="0.8696" y="-3" relative="1" as="geometry">
<mxPoint x="3" y="81" as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="VISHqFL7TcA8I7J5W86J-5" value="<font color="#007fff"><b>// 1&nbsp;</b></font><br style="font-size: 11px;">DebuggingClassWriter cw = this.<b>getClassVisitor</b>();<br><font color="#007fff"><b>// 2</b> 这里 transform() 没有做任何转换参数原样返回,这里 cg 是 Enhancer 实例引用<br style="font-size: 11px;"></font>this.transform(cg).<b>generateClass</b>(cw);<br><font color="#007fff"><b>// 3</b> 以 Byte 数组形式输出 ClassWriter 中字节码</font><br style="font-size: 11px;">return this.transform(cw.<b>toByteArray</b>());" style="rounded=1;whiteSpace=wrap;html=1;align=left;fontSize=11;" parent="1" vertex="1">
<mxGeometry x="280" y="160" width="440" height="80" as="geometry" />
</mxCell>
<mxCell id="VISHqFL7TcA8I7J5W86J-21" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="VISHqFL7TcA8I7J5W86J-7" target="VISHqFL7TcA8I7J5W86J-20" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="VISHqFL7TcA8I7J5W86J-7" value="return new <b>DebuggingClassWriter</b>(2);" style="rounded=1;whiteSpace=wrap;html=1;align=left;fontSize=11;" parent="1" vertex="1">
<mxGeometry x="760" y="160" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="FzdVbH49xBQuPaiEanxh-2" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="VISHqFL7TcA8I7J5W86J-10" target="FzdVbH49xBQuPaiEanxh-1" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="VISHqFL7TcA8I7J5W86J-10" value="<b>Enhancer</b>#<b>generateClass</b>(cw)<br><font color="#007fff"><b>内部通过ClassEmitter生成类各部分的字节码并写入 ClassWriter 对象</b><br></font>" style="rounded=1;whiteSpace=wrap;html=1;align=center;fontSize=11;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
<mxGeometry x="760" y="260" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="10TpCgqnUDmNamHutM36-3" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="VISHqFL7TcA8I7J5W86J-12" target="10TpCgqnUDmNamHutM36-2">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="VISHqFL7TcA8I7J5W86J-12" value="ClassWriter#<b>toByteArray</b>()<br><b><font color="#007fff">还支持输出 .class .asm 文件</font></b>" style="rounded=1;whiteSpace=wrap;html=1;align=center;fontSize=11;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="760" y="1800" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="VISHqFL7TcA8I7J5W86J-17" value="<p style="margin: 4px 0px 0px; text-align: center;"><b>ClassVisitor</b><br style="font-size: 11px;"></p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px;"><font color="#007fff"><b>提供了一组 visit 方法用于构建 Class 字节码</b></font></p><p style="margin: 0px 0px 0px 4px;"><br></p><p style="margin: 0px 0px 0px 4px;"><font color="#007fff">// ASM API 版本,默认 ASM9</font></p><p style="margin: 0px 0px 0px 4px;">protected final int api;<br></p><p style="margin: 0px 0px 0px 4px;"><font color="#007fff">// 装饰器模式</font></p><p style="margin: 0px 0px 0px 4px;">protected <b>ClassVisitor</b> cv;<br></p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px;"><font color="#007fff">重要方法:</font></p><p style="margin: 0px 0px 0px 4px;"><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=11;fontFamily=Helvetica;html=1;whiteSpace=wrap;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
<mxGeometry x="-440" y="80" width="400" height="200" as="geometry" />
</mxCell>
<mxCell id="VISHqFL7TcA8I7J5W86J-19" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;endArrow=block;endFill=1;" parent="1" source="VISHqFL7TcA8I7J5W86J-18" target="VISHqFL7TcA8I7J5W86J-17" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="VISHqFL7TcA8I7J5W86J-18" value="<p style="margin: 4px 0px 0px; text-align: center;"><b>DebuggingClassWriter</b><br style="font-size: 11px;"></p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px;"><b><font color="#007fff">这个是 Spring CgLib 中的类</font></b></p><p style="margin: 0px 0px 0px 4px;"><b><font color="#007fff"><br></font></b></p><p style="margin: 0px 0px 0px 4px;">public static final String DEBUG_LOCATION_PROPERTY = <br>&nbsp; &nbsp; "cglib.debugLocation";</p><p style="margin: 0px 0px 0px 4px;">private static String <b>debugLocation</b> =<br>&nbsp; &nbsp; System.getProperty("<b>cglib.debugLocation</b>");</p><p style="margin: 0px 0px 0px 4px;">private static Constructor traceCtor;</p><p style="margin: 0px 0px 0px 4px;"><font color="#007fff">// 生成代理类的全限定名</font></p><p style="margin: 0px 0px 0px 4px;">private String <b>className</b>;</p><p style="margin: 0px 0px 0px 4px;"><font color="#007fff">// 被增强的类的全限定名</font></p><p style="margin: 0px 0px 0px 4px;"></p><p style="margin: 0px 0px 0px 4px;">private String <b>superName</b>;</p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px;"><br style="font-size: 11px;"></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=11;fontFamily=Helvetica;html=1;whiteSpace=wrap;" parent="1" vertex="1">
<mxGeometry x="-440" y="320" width="400" height="200" as="geometry" />
</mxCell>
<mxCell id="VISHqFL7TcA8I7J5W86J-20" value="super(Constants.ASM_API, new <b>ClassWriter</b>(flags));" style="rounded=1;whiteSpace=wrap;html=1;align=left;fontSize=11;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="1000" y="160" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="VISHqFL7TcA8I7J5W86J-23" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;endArrow=block;endFill=1;" parent="1" source="VISHqFL7TcA8I7J5W86J-22" target="VISHqFL7TcA8I7J5W86J-17" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="FzdVbH49xBQuPaiEanxh-57" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.25;exitDx=0;exitDy=0;endArrow=open;endFill=0;" parent="1" source="VISHqFL7TcA8I7J5W86J-22" target="FzdVbH49xBQuPaiEanxh-56" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="VISHqFL7TcA8I7J5W86J-22" value="<p style="margin: 4px 0px 0px; text-align: center;"><b>ClassWriter</b><br style="font-size: 11px;"></p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px;"><b><font color="#007fff">对应 Class 字节码结构, Class中各个部分的字节码最终都是要以byte形式写到这个类中</font></b></p><p style="margin: 0px 0px 0px 4px;"><br></p><p style="margin: 0px 0px 0px 4px;">public static final int COMPUTE_MAXS = 1;<br></p><p style="margin: 0px 0px 0px 4px;">public static final int COMPUTE_FRAMES = 2;<br></p><p style="margin: 0px 0px 0px 4px;">private final int <b>flags</b>;<br></p><p style="margin: 0px 0px 0px 4px;"><font color="#007fff">// 版本号,低16位是主版本号,高16位是次版本号</font></p><p style="margin: 0px 0px 0px 4px;">private int <b>version</b>;<br></p><p style="margin: 0px 0px 0px 4px;"><font color="#007fff"><b>// 符号表</b></font></p><p style="margin: 0px 0px 0px 4px;">private final SymbolTable <b>symbolTable</b>;<br></p><p style="margin: 0px 0px 0px 4px;"><font color="#007fff">// Class 的访问描述符,比如:ACC_PUBLIC</font></p><p style="margin: 0px 0px 0px 4px;">private int <b>accessFlags</b>;<br></p><p style="margin: 0px 0px 0px 4px;"><font color="#007fff">// classname 在常量池中的索引</font></p><p style="margin: 0px 0px 0px 4px;">private int <b>thisClass</b>;<br></p><p style="margin: 0px 0px 0px 4px;"><font color="#007fff">// 父类名在常量池中的索引</font></p><p style="margin: 0px 0px 0px 4px;">private int <b>superClass</b>;</p><p style="margin: 0px 0px 0px 4px;">private int <b>interfaceCount</b>;<br></p><p style="margin: 0px 0px 0px 4px;">private int[] <b>interfaces</b>;<br></p><p style="margin: 0px 0px 0px 4px;"><font color="#007fff">// 后面的对象,基本都包含 symbolTable, 以及在symbolTable 中的索引</font></p><p style="margin: 0px 0px 0px 4px;">private FieldWriter <b>firstField</b>;<br></p><p style="margin: 0px 0px 0px 4px;">private FieldWriter <b>lastField</b>;</p><p style="margin: 0px 0px 0px 4px;">private MethodWriter <b>firstMethod</b>;</p><p style="margin: 0px 0px 0px 4px;">private MethodWriter <b>lastMethod</b>;</p><p style="margin: 0px 0px 0px 4px;">private int numberOfInnerClasses;</p><p style="margin: 0px 0px 0px 4px;">private ByteVector <b>innerClasses</b>;</p><p style="margin: 0px 0px 0px 4px;">private int enclosingClassIndex;</p><p style="margin: 0px 0px 0px 4px;">private int enclosingMethodIndex;</p><p style="margin: 0px 0px 0px 4px;">private int signatureIndex;</p><p style="margin: 0px 0px 0px 4px;">private int sourceFileIndex;</p><p style="margin: 0px 0px 0px 4px;">private ByteVector debugExtension;</p><p style="margin: 0px 0px 0px 4px;">private AnnotationWriter lastRuntimeVisibleAnnotation;</p><p style="margin: 0px 0px 0px 4px;">private AnnotationWriter lastRuntimeInvisibleAnnotation;</p><p style="margin: 0px 0px 0px 4px;">private AnnotationWriter lastRuntimeVisibleTypeAnnotation;</p><p style="margin: 0px 0px 0px 4px;">private AnnotationWriter lastRuntimeInvisibleTypeAnnotation;</p><p style="margin: 0px 0px 0px 4px;">private ModuleWriter moduleWriter;</p><p style="margin: 0px 0px 0px 4px;">private int nestHostClassIndex;</p><p style="margin: 0px 0px 0px 4px;">private int numberOfNestMemberClasses;</p><p style="margin: 0px 0px 0px 4px;">private ByteVector nestMemberClasses;</p><p style="margin: 0px 0px 0px 4px;">private int numberOfPermittedSubclasses;</p><p style="margin: 0px 0px 0px 4px;">private ByteVector permittedSubclasses;</p><p style="margin: 0px 0px 0px 4px;">private RecordComponentWriter firstRecordComponent;</p><p style="margin: 0px 0px 0px 4px;">private RecordComponentWriter lastRecordComponent;</p><p style="margin: 0px 0px 0px 4px;">private Attribute firstAttribute;</p><p style="margin: 0px 0px 0px 4px;">private int compute;</p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px;"><br style="font-size: 11px;"></p><p style="margin: 0px 0px 0px 4px;"><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=11;fontFamily=Helvetica;html=1;whiteSpace=wrap;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
<mxGeometry x="-880" y="320" width="400" height="640" as="geometry" />
</mxCell>
<mxCell id="FzdVbH49xBQuPaiEanxh-51" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1.001;exitY=0.372;exitDx=0;exitDy=0;exitPerimeter=0;" parent="1" source="FzdVbH49xBQuPaiEanxh-1" target="FzdVbH49xBQuPaiEanxh-50" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="FzdVbH49xBQuPaiEanxh-63" value="1" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="FzdVbH49xBQuPaiEanxh-51" vertex="1" connectable="0">
<mxGeometry x="0.7206" y="-2" relative="1" as="geometry">
<mxPoint as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="FzdVbH49xBQuPaiEanxh-61" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1.001;exitY=0.592;exitDx=0;exitDy=0;exitPerimeter=0;" parent="1" source="FzdVbH49xBQuPaiEanxh-1" target="FzdVbH49xBQuPaiEanxh-60" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="FzdVbH49xBQuPaiEanxh-67" value="2" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="FzdVbH49xBQuPaiEanxh-61" vertex="1" connectable="0">
<mxGeometry x="0.7069" relative="1" as="geometry">
<mxPoint as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="FzdVbH49xBQuPaiEanxh-65" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.998;exitY=0.768;exitDx=0;exitDy=0;exitPerimeter=0;" parent="1" source="FzdVbH49xBQuPaiEanxh-1" target="FzdVbH49xBQuPaiEanxh-64" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="FzdVbH49xBQuPaiEanxh-66" value="3" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="FzdVbH49xBQuPaiEanxh-65" vertex="1" connectable="0">
<mxGeometry x="0.3732" relative="1" as="geometry">
<mxPoint x="10" y="31" as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="FzdVbH49xBQuPaiEanxh-1" value="<div style="font-size: 10px;">public void generateClass(ClassVisitor v) throws Exception {</div><div style="font-size: 10px;"><font color="#007fff">&nbsp; &nbsp; // <b>被代理增强的目标类型</b>为null就增强Object类型</font></div><div style="font-size: 10px;">&nbsp; &nbsp; Class sc = (superclass == null) ? Object.class : superclass;</div><div style="font-size: 10px;"><font color="#007fff">&nbsp; &nbsp; // <b>不能增强 final 修饰的类</b></font></div><div style="font-size: 10px;">&nbsp; &nbsp; if (TypeUtils.<b>isFinal</b>(sc.getModifiers()))</div><div style="font-size: 10px;">&nbsp; &nbsp; &nbsp; &nbsp; throw new IllegalArgumentException("Cannot subclass final class " + sc.getName());</div><div style="font-size: 10px;">&nbsp; &nbsp; <font color="#007fff">// <b>获取目标类型所有构造方法,然后过滤出 public protected (protectedOk=true) default (samePackageOk=true) 的构造器</b></font></div><div style="font-size: 10px;">&nbsp; &nbsp; List constructors = new ArrayList(Arrays.asList(sc.getDeclaredConstructors()));</div><div style="font-size: 10px;">&nbsp; &nbsp; filterConstructors(sc, constructors);</div><div style="font-size: 10px;"><br></div><div style="font-size: 10px;">&nbsp; &nbsp; List actualMethods = new ArrayList();</div><div style="font-size: 10px;">&nbsp; &nbsp; List interfaceMethods = new ArrayList();</div><div style="font-size: 10px;">&nbsp; &nbsp; final Set forcePublic = new HashSet();</div><div style="font-size: 10px;"><b><font color="#007fff">&nbsp; &nbsp; //依次并递归从目标类型、目标类型实现的接口类型中提取所有方法(用的getDeclaredMethods()</font><font color="#007fff">)存储到 actualMethods</font></b></div><div style="font-size: 10px;"><b><font color="#007fff">&nbsp; &nbsp; //依次并递归从 interfaces 类型中提取所有方法存储到 interfaceMethods 并添加到 actualMethods, 如果 forcePublic !=null, 为 interfaceMethods 中每个方法类型创建 Method 实例存储到 forcePublic</font></b></div><div style="font-size: 10px;"><b><font color="#007fff">&nbsp; &nbsp; //最后还需要过滤掉 actualMethods 中带有 static 、final 修饰符以及重复的方法类型</font></b></div><div style="font-size: 10px;"><font style="" color="#007fff">&nbsp; &nbsp; //内部代码比较简单不展开了</font></div><div style="font-size: 10px;">&nbsp; &nbsp; <b>getMethods</b>(sc, interfaces, actualMethods, interfaceMethods, forcePublic);</div><div style="font-size: 10px;"><br style="font-size: 10px;"></div><div style="font-size: 10px;"><b><font color="#007fff">&nbsp; &nbsp; // 将 actualMethods 进行转换,转换规则:将 abstract native synchronized 方法标记为非抽象、非本地、非同步方法,然后再标记为 final 方法,最后返回 MethodInfo&nbsp;</font></b></div><div style="font-size: 10px;">&nbsp; &nbsp; List <b>methods</b> = CollectionUtils.transform(actualMethods, new Transformer() { <font color="#007fff">// methods 中存储的是 MethodInfo&nbsp;</font></div><div style="font-size: 10px;">&nbsp; &nbsp; &nbsp; &nbsp; public Object transform(Object value) {</div><div style="font-size: 10px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Method method = (Method) value;</div><div style="font-size: 10px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; int modifiers = <b>Constants.ACC_FINAL</b></div><div style="font-size: 10px;"><b>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | (method.getModifiers()</b></div><div style="font-size: 10px;"><b>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &amp; ~Constants.ACC_ABSTRACT</b></div><div style="font-size: 10px;"><b>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &amp; ~Constants.ACC_NATIVE</b></div><div style="font-size: 10px;"><b>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &amp; ~Constants.ACC_SYNCHRONIZED</b>);</div><div style="font-size: 10px;"><b><font color="#007fff"><span style=""><span style="">&nbsp;&nbsp;&nbsp;&nbsp;</span></span>&nbsp; &nbsp; // 如果有设置 forcePublic 将方法从 protected 重新标记为 public</font><br></b></div><div style="font-size: 10px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (forcePublic.contains(MethodWrapper.create(method))) {</div><div style="font-size: 10px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; modifiers = (modifiers &amp; ~Constants.ACC_PROTECTED) | Constants.ACC_PUBLIC;</div><div style="font-size: 10px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div style="font-size: 10px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return ReflectUtils.getMethodInfo(method, modifiers);</div><div style="font-size: 10px;">&nbsp; &nbsp; &nbsp; &nbsp; }</div><div style="font-size: 10px;">&nbsp; &nbsp; });</div><div style="font-size: 10px;"><br style="font-size: 10px;"></div><div style="font-size: 10px;"><font color="#007fff"><b>&nbsp; &nbsp; // 后面开始构造代理类字节码主体</b></font></div><div style="font-size: 10px;">&nbsp; &nbsp; ClassEmitter <b>e</b> = new <b>ClassEmitter</b>(v);</div><div style="font-size: 10px;"><span style="background-color: initial;">&nbsp; &nbsp; if (currentData == null) {</span></div><font color="#007fff"><b>&nbsp; &nbsp; &nbsp; &nbsp; // 1 代理类类型基本信息写入ClassWriter<br></b></font><div style="font-size: 10px;">&nbsp; &nbsp; &nbsp; &nbsp; e.<b>begin_class</b>(Constants.V1_8,&nbsp; <font color="#007fff">//主版本号</font></div><div style="font-size: 10px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Constants.ACC_PUBLIC, <font color="#007fff">//类型修饰符,也称Class的访问标记</font></div><div style="font-size: 10px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; getClassName(),</div><div style="font-size: 10px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Type.getType(sc), <font color="#007fff">// 父类类型描述</font></div><div style="font-size: 10px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (useFactory ?</div><div style="font-size: 10px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; TypeUtils.<b>add</b>(TypeUtils.getTypes(interfaces), FACTORY) : <font color="#007fff">//额外添加要实现的接口&nbsp;org.springframework.cglib.proxy.<b>Factory</b></font></div><div style="font-size: 10px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; TypeUtils.<b>getTypes</b>(interfaces)),</div><div style="font-size: 10px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Constants.SOURCE_FILE);<font color="#007fff"> //&nbsp;&lt;generated&gt;</font></div><div style="font-size: 10px;">&nbsp; &nbsp; }</div><div style="font-size: 10px;">&nbsp; &nbsp; else {</div><div style="font-size: 10px;">&nbsp; &nbsp; &nbsp; &nbsp; e.begin_class(Constants.V1_8,</div><div style="font-size: 10px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Constants.ACC_PUBLIC,</div><div style="font-size: 10px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; getClassName(),</div><div style="font-size: 10px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; null,</div><div style="font-size: 10px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; new Type[]{FACTORY},</div><div style="font-size: 10px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Constants.SOURCE_FILE);</div><div style="font-size: 10px;">&nbsp; &nbsp; }</div><div style="font-size: 10px;"><b>&nbsp; &nbsp; <font color="#007fff">// 用于获取 sc 构造方法的方法信息 MethodInfo (包括方法签名、ClassInfo、方法修饰符、返回异常类型)</font></b></div><div style="font-size: 10px;">&nbsp; &nbsp; List <b>constructorInfo</b> = CollectionUtils.transform(constructors, MethodInfoTransformer.getInstance());</div><div style="font-size: 10px;"><font color="#007fff">&nbsp; &nbsp; // 定义 private boolean&nbsp;CGLIB$BOUND;&nbsp; 不过在 class 文件中并不是表示为这样</font></div><div style="font-size: 10px;">&nbsp; &nbsp; e.declare_field(Constants.ACC_PRIVATE, BOUND_FIELD, Type.BOOLEAN_TYPE, null);</div><div style="font-size: 10px;"><font color="#007fff">&nbsp; &nbsp; // 定义 public static Object&nbsp;CGLIB$FACTORY_DATA;</font></div><div style="font-size: 10px;">&nbsp; &nbsp; e.declare_field(Constants.ACC_PUBLIC | Constants.ACC_STATIC, FACTORY_DATA_FIELD, OBJECT_TYPE, null);</div><div style="font-size: 10px;">&nbsp; &nbsp; if (!interceptDuringConstruction) { <font color="#007fff">//是否拦截构造方法?</font></div><div style="font-size: 10px;">&nbsp; &nbsp; &nbsp; &nbsp; e.declare_field(Constants.ACC_PRIVATE, CONSTRUCTED_FIELD, Type.BOOLEAN_TYPE, null);</div><div style="font-size: 10px;">&nbsp; &nbsp; }</div><div style="font-size: 10px;"><font color="#007fff">&nbsp; &nbsp; // 定义 private final static ThreadLocal&nbsp;CGLIB$THREAD_CALLBACKS</font></div><div style="font-size: 10px;">&nbsp; &nbsp; e.declare_field(Constants.PRIVATE_FINAL_STATIC, THREAD_CALLBACKS_FIELD, THREAD_LOCAL, null);</div><div style="font-size: 10px;"><font color="#007fff">&nbsp; &nbsp; // 定义 <b>private final static&nbsp;Callback[]&nbsp;CGLIB$STATIC_CALLBACKS</b></font></div><div style="font-size: 10px;">&nbsp; &nbsp; e.declare_field(Constants.PRIVATE_FINAL_STATIC, STATIC_CALLBACKS_FIELD, CALLBACK_ARRAY, null);</div><div style="font-size: 10px;">&nbsp; &nbsp; if (serialVersionUID != null) {</div><div style="font-size: 10px;">&nbsp; &nbsp; &nbsp; &nbsp; e.declare_field(Constants.PRIVATE_FINAL_STATIC, Constants.SUID_FIELD_NAME, Type.LONG_TYPE, serialVersionUID);</div><div style="font-size: 10px;">&nbsp; &nbsp; }</div><div style="font-size: 10px;">&nbsp; &nbsp;<font color="#007fff"> <b>// 2 为代理方法增强类型(MethodInterceptor Dispatcher)创建字段, 比如</b></font></div><div style="font-size: 10px;"><font color="#007fff">&nbsp; &nbsp; // private</font><font color="#007fff">&nbsp;MethodInterceptor CGLIB#CALLBACK_0</font></div><div style="font-size: 10px;">&nbsp; &nbsp; for (int i = 0; i &lt; callbackTypes.length; i++) {</div><div style="font-size: 10px;">&nbsp; &nbsp; &nbsp; &nbsp; e.<b>declare_field</b>(Constants.ACC_PRIVATE, getCallbackField(i), <b>callbackTypes</b>[i], null);</div><div style="font-size: 10px;">&nbsp; &nbsp; }</div><div style="font-size: 10px;"><font color="#007fff">&nbsp; &nbsp; // private static Object&nbsp;CGLIB$CALLBACK_FILTER</font></div><div style="font-size: 10px;">&nbsp; &nbsp; e.declare_field(Constants.ACC_PRIVATE | Constants.ACC_STATIC, CALLBACK_FILTER_FIELD, OBJECT_TYPE, null);</div><div style="font-size: 10px;"><br style="font-size: 10px;"></div><div style="font-size: 10px;">&nbsp; &nbsp; if (currentData == null) {</div><div style="font-size: 10px;"><font color="#007fff"><b><span style=""><span style="white-space: pre;">&nbsp;&nbsp;&nbsp;&nbsp; </span></span>// 3 创建代理方法,遍历所有要创建的方法(结合MethodInfo Method信息)<br></b></font></div><div style="font-size: 10px;">&nbsp; &nbsp; &nbsp; &nbsp; <b>emitMethods</b>(e, methods, actualMethods);</div><div style="font-size: 10px;"><font color="#007fff"><span style=""><span style="white-space: pre;">&nbsp;&nbsp;&nbsp;&nbsp; </span></span>//创建构造方法</font><br></div><div style="font-size: 10px;">&nbsp; &nbsp; &nbsp; &nbsp; <b>emitConstructors</b>(e, constructorInfo);</div><div style="font-size: 10px;">&nbsp; &nbsp; }</div><div style="font-size: 10px;">&nbsp; &nbsp; else {</div><div style="font-size: 10px;"><font color="#007fff">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;//创建默认构造方法</font></div><div style="font-size: 10px;">&nbsp; &nbsp; &nbsp; &nbsp; emitDefaultConstructor(e);</div><div style="font-size: 10px;">&nbsp; &nbsp; }</div><div style="font-size: 10px;">&nbsp; &nbsp; //&nbsp;</div><div style="font-size: 10px;">&nbsp; &nbsp; emitSetThreadCallbacks(e);</div><div style="font-size: 10px;">&nbsp; &nbsp; emitSetStaticCallbacks(e);</div><div style="font-size: 10px;">&nbsp; &nbsp; emitBindCallbacks(e);</div><div style="font-size: 10px;"><br style="font-size: 10px;"></div><div style="font-size: 10px;">&nbsp; &nbsp; if (useFactory || currentData != null) {</div><div style="font-size: 10px;">&nbsp; &nbsp; &nbsp; &nbsp; int[] keys = getCallbackKeys();</div><div style="font-size: 10px;">&nbsp; &nbsp; &nbsp; &nbsp; emitNewInstanceCallbacks(e);</div><div style="font-size: 10px;">&nbsp; &nbsp; &nbsp; &nbsp; emitNewInstanceCallback(e);</div><div style="font-size: 10px;">&nbsp; &nbsp; &nbsp; &nbsp; emitNewInstanceMultiarg(e, constructorInfo);</div><div style="font-size: 10px;">&nbsp; &nbsp; &nbsp; &nbsp; emitGetCallback(e, keys);</div><div style="font-size: 10px;">&nbsp; &nbsp; &nbsp; &nbsp; emitSetCallback(e, keys);</div><div style="font-size: 10px;">&nbsp; &nbsp; &nbsp; &nbsp; emitGetCallbacks(e);</div><div style="font-size: 10px;">&nbsp; &nbsp; &nbsp; &nbsp; emitSetCallbacks(e);</div><div style="font-size: 10px;">&nbsp; &nbsp; }</div><div style="font-size: 10px;"><br style="font-size: 10px;"></div><div style="font-size: 10px;">&nbsp; &nbsp; e.end_class();</div><div style="font-size: 10px;">}</div>" style="rounded=1;whiteSpace=wrap;html=1;align=left;fontSize=10;arcSize=1;" parent="1" vertex="1">
<mxGeometry x="1000" y="260" width="560" height="1380" as="geometry" />
</mxCell>
<mxCell id="FzdVbH49xBQuPaiEanxh-5" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;endArrow=block;endFill=1;" parent="1" source="FzdVbH49xBQuPaiEanxh-3" target="FzdVbH49xBQuPaiEanxh-4" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="FzdVbH49xBQuPaiEanxh-3" value="<p style="margin: 4px 0px 0px; text-align: center;"><b>Enhancer</b><br style="font-size: 11px;"></p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px;"><font color="#007fff"><b>可以将 Enhancer 理解为代理类生成配置</b></font></p><p style="margin: 0px 0px 0px 4px;"><br></p><p style="margin: 0px 0px 0px 4px;">private <b>EnhancerFactoryData</b> <b>currentData</b>;</p><p style="margin: 0px 0px 0px 4px;"><br></p><p style="margin: 0px 0px 0px 4px;">private Object currentKey;</p><p style="margin: 0px 0px 0px 4px;"><br></p><p style="margin: 0px 0px 0px 4px;">private Class[] interfaces;</p><p style="margin: 0px 0px 0px 4px;"><font color="#007fff"><b>// 用于判断目标方法应该使用哪种方式增强,比如 CglibAopProxy 中提供了7种方式,分别对应一种 callbackType</b></font></p><p style="margin: 0px 0px 0px 4px; font-size: 10px;"><font style="font-size: 10px;" color="#007fff">&nbsp; &nbsp; private static final int <b>AOP_PROXY</b> = 0;&nbsp; // AOP_PROXY 使用 MethodInteceptor<span style=""></span></font></p><p style="margin: 0px 0px 0px 4px; font-size: 10px;"><font style="font-size: 10px;" color="#007fff"><span style=""><span style=""><span style="white-space: pre;">&nbsp;&nbsp;&nbsp;&nbsp;</span></span>private static final int INVOKE_TARGET = 1;</span></font></p><p style="margin: 0px 0px 0px 4px; font-size: 10px;"><font style="font-size: 10px;" color="#007fff"><span style=""><span style=""><span style="white-space: pre;">&nbsp;&nbsp;&nbsp;&nbsp;</span></span>private static final int NO_OVERRIDE = 2;</span></font></p><p style="margin: 0px 0px 0px 4px; font-size: 10px;"><font style="font-size: 10px;" color="#007fff"><span style=""><span style=""><span style="white-space: pre;">&nbsp;&nbsp;&nbsp;&nbsp;</span></span>private static final int DISPATCH_TARGET = 3;</span></font></p><p style="margin: 0px 0px 0px 4px; font-size: 10px;"><font style="font-size: 10px;" color="#007fff"><span style=""><span style=""><span style="white-space: pre;">&nbsp;&nbsp;&nbsp;&nbsp;</span></span>private static final int DISPATCH_ADVISED = 4;</span></font></p><p style="margin: 0px 0px 0px 4px; font-size: 10px;"><font style="font-size: 10px;" color="#007fff"><span style=""><span style=""><span style="white-space: pre;">&nbsp;&nbsp;&nbsp;&nbsp;</span></span>private static final int INVOKE_EQUALS = 5;</span></font></p><p style="margin: 0px 0px 0px 4px; font-size: 10px;"></p><p style="margin: 0px 0px 0px 4px; font-size: 10px;"><font style="font-size: 10px;" color="#007fff"><span style=""><span style="white-space: pre;">&nbsp;&nbsp;&nbsp;&nbsp;</span>private static final int INVOKE_HASHCODE = 6;</span></font></p><p style="margin: 0px 0px 0px 4px;">private CallbackFilter <b>filter</b>;</p><p style="margin: 0px 0px 0px 4px;"><br></p><p style="margin: 0px 0px 0px 4px;">private Callback[] callbacks;</p><p style="margin: 0px 0px 0px 4px;"><font color="#007fff"><b>// 增强逻辑类型,比如 MethodInterceptor Dispatcher</b></font></p><p style="margin: 0px 0px 0px 4px;">private Type[] <b>callbackTypes</b>;</p><p style="margin: 0px 0px 0px 4px;"><br></p><p style="margin: 0px 0px 0px 4px;">private boolean validateCallbackTypes;</p><p style="margin: 0px 0px 0px 4px;"><br></p><p style="margin: 0px 0px 0px 4px;">private boolean classOnly;</p><p style="margin: 0px 0px 0px 4px;"><font color="#007fff">// 被代理增强的目标类型(比如测试中的 TransferService),此字段为null则以 Object 作为目标类型</font></p><p style="margin: 0px 0px 0px 4px;">private Class <b>superclass</b>;</p><p style="margin: 0px 0px 0px 4px;"><font color="#007fff">// 参数类型</font></p><p style="margin: 0px 0px 0px 4px;">private Class[] argumentTypes;</p><p style="margin: 0px 0px 0px 4px;"><font color="#007fff">// 参数列表</font></p><p style="margin: 0px 0px 0px 4px;">private Object[] arguments;</p><p style="margin: 0px 0px 0px 4px;"><font color="#007fff">// 代理类是否应该实现 Factory 接口,即</font><span style="background-color: initial;"><font color="#007fff">org.springframework.cglib.proxy.<b>Factory</b></font></span></p><p style="margin: 0px 0px 0px 4px;">private boolean <b>useFactory</b> = true;</p><p style="margin: 0px 0px 0px 4px;"><br></p><p style="margin: 0px 0px 0px 4px;">private Long serialVersionUID;</p><p style="margin: 0px 0px 0px 4px;"><br></p><p style="margin: 0px 0px 0px 4px;">private boolean interceptDuringConstruction = true;</p><p style="margin: 0px 0px 0px 4px;"><br></p><p style="margin: 0px 0px 0px 4px;"><br></p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px;"><br style="font-size: 11px;"></p><p style="margin: 0px 0px 0px 4px;"><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=11;fontFamily=Helvetica;html=1;whiteSpace=wrap;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
<mxGeometry x="-1760" y="440" width="400" height="600" as="geometry" />
</mxCell>
<mxCell id="FzdVbH49xBQuPaiEanxh-4" value="<p style="margin: 4px 0px 0px; text-align: center;"><b>AbstractClassGenerator&lt;T&gt;&nbsp;</b><span style="background-color: initial;">implements ClassGenerator</span></p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px;"><br></p><p style="margin: 0px 0px 0px 4px;">private GeneratorStrategy strategy = DefaultGeneratorStrategy.INSTANCE;</p><p style="margin: 0px 0px 0px 4px;"><br></p><p style="margin: 0px 0px 0px 4px;">private NamingPolicy namingPolicy = DefaultNamingPolicy.INSTANCE;</p><p style="margin: 0px 0px 0px 4px;"><br></p><p style="margin: 0px 0px 0px 4px;">private Source source;</p><p style="margin: 0px 0px 0px 4px;"><br></p><p style="margin: 0px 0px 0px 4px;">private ClassLoader classLoader;</p><p style="margin: 0px 0px 0px 4px;"><br></p><p style="margin: 0px 0px 0px 4px;">private Class contextClass;</p><p style="margin: 0px 0px 0px 4px;"><br></p><p style="margin: 0px 0px 0px 4px;">private String namePrefix;</p><p style="margin: 0px 0px 0px 4px;"><br></p><p style="margin: 0px 0px 0px 4px;">private Object key;</p><p style="margin: 0px 0px 0px 4px;"><br></p><p style="margin: 0px 0px 0px 4px;">private boolean useCache = DEFAULT_USE_CACHE;</p><p style="margin: 0px 0px 0px 4px;"><font color="#007fff">// 要生成的代理类的类名</font></p><p style="margin: 0px 0px 0px 4px;">private String <b>className</b>;</p><p style="margin: 0px 0px 0px 4px;"><br></p><p style="margin: 0px 0px 0px 4px;">private boolean attemptLoad;</p><p style="margin: 0px 0px 0px 4px;"><br></p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px;"><br style="font-size: 11px;"></p><p style="margin: 0px 0px 0px 4px;"><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=11;fontFamily=Helvetica;html=1;whiteSpace=wrap;" parent="1" vertex="1">
<mxGeometry x="-1760" y="40" width="400" height="360" as="geometry" />
</mxCell>
<mxCell id="FzdVbH49xBQuPaiEanxh-6" value="Enhancer" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" parent="1" vertex="1">
<mxGeometry x="1245" y="230" width="70" height="30" as="geometry" />
</mxCell>
<mxCell id="FzdVbH49xBQuPaiEanxh-7" value="final" style="rounded=0;whiteSpace=wrap;html=1;fontSize=10;" parent="1" vertex="1">
<mxGeometry x="480" y="520" width="40" height="40" as="geometry" />
</mxCell>
<mxCell id="FzdVbH49xBQuPaiEanxh-8" value="<div style="font-size: 9px;">synch</div><div style="font-size: 9px;">ronized</div>" style="rounded=0;whiteSpace=wrap;html=1;fontSize=9;" parent="1" vertex="1">
<mxGeometry x="440" y="520" width="40" height="40" as="geometry" />
</mxCell>
<mxCell id="FzdVbH49xBQuPaiEanxh-9" value="<font style="font-size: 10px;">bridge</font>" style="rounded=0;whiteSpace=wrap;html=1;fontSize=10;" parent="1" vertex="1">
<mxGeometry x="400" y="520" width="40" height="40" as="geometry" />
</mxCell>
<mxCell id="FzdVbH49xBQuPaiEanxh-10" value="varargs" style="rounded=0;whiteSpace=wrap;html=1;fontSize=10;" parent="1" vertex="1">
<mxGeometry x="360" y="520" width="40" height="40" as="geometry" />
</mxCell>
<mxCell id="FzdVbH49xBQuPaiEanxh-11" value="public" style="rounded=0;whiteSpace=wrap;html=1;fontSize=10;" parent="1" vertex="1">
<mxGeometry x="640" y="520" width="40" height="40" as="geometry" />
</mxCell>
<mxCell id="FzdVbH49xBQuPaiEanxh-12" value="private" style="rounded=0;whiteSpace=wrap;html=1;fontSize=10;" parent="1" vertex="1">
<mxGeometry x="600" y="520" width="40" height="40" as="geometry" />
</mxCell>
<mxCell id="FzdVbH49xBQuPaiEanxh-13" value="protected" style="rounded=0;whiteSpace=wrap;html=1;fontSize=9;" parent="1" vertex="1">
<mxGeometry x="560" y="520" width="40" height="40" as="geometry" />
</mxCell>
<mxCell id="FzdVbH49xBQuPaiEanxh-14" value="static" style="rounded=0;whiteSpace=wrap;html=1;fontSize=10;" parent="1" vertex="1">
<mxGeometry x="520" y="520" width="40" height="40" as="geometry" />
</mxCell>
<mxCell id="FzdVbH49xBQuPaiEanxh-31" value="synthetic" style="rounded=0;whiteSpace=wrap;html=1;fontSize=9;" parent="1" vertex="1">
<mxGeometry x="160" y="520" width="40" height="40" as="geometry" />
</mxCell>
<mxCell id="FzdVbH49xBQuPaiEanxh-32" value="" style="rounded=0;whiteSpace=wrap;html=1;fontSize=10;" parent="1" vertex="1">
<mxGeometry x="120" y="520" width="40" height="40" as="geometry" />
</mxCell>
<mxCell id="FzdVbH49xBQuPaiEanxh-33" value="<font style="font-size: 8px;">mandated</font>" style="rounded=0;whiteSpace=wrap;html=1;fontSize=10;" parent="1" vertex="1">
<mxGeometry x="80" y="520" width="40" height="40" as="geometry" />
</mxCell>
<mxCell id="FzdVbH49xBQuPaiEanxh-34" value="" style="rounded=0;whiteSpace=wrap;html=1;fontSize=10;" parent="1" vertex="1">
<mxGeometry x="40" y="520" width="40" height="40" as="geometry" />
</mxCell>
<mxCell id="FzdVbH49xBQuPaiEanxh-35" value="native" style="rounded=0;whiteSpace=wrap;html=1;fontSize=10;" parent="1" vertex="1">
<mxGeometry x="320" y="520" width="40" height="40" as="geometry" />
</mxCell>
<mxCell id="FzdVbH49xBQuPaiEanxh-36" value="" style="rounded=0;whiteSpace=wrap;html=1;fontSize=10;" parent="1" vertex="1">
<mxGeometry x="280" y="520" width="40" height="40" as="geometry" />
</mxCell>
<mxCell id="FzdVbH49xBQuPaiEanxh-37" value="abstract" style="rounded=0;whiteSpace=wrap;html=1;fontSize=10;" parent="1" vertex="1">
<mxGeometry x="240" y="520" width="40" height="40" as="geometry" />
</mxCell>
<mxCell id="FzdVbH49xBQuPaiEanxh-38" value="strict" style="rounded=0;whiteSpace=wrap;html=1;fontSize=10;" parent="1" vertex="1">
<mxGeometry x="200" y="520" width="40" height="40" as="geometry" />
</mxCell>
<mxCell id="FzdVbH49xBQuPaiEanxh-39" value="方法 (Method) 的修饰符 (Modifier)" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" parent="1" vertex="1">
<mxGeometry x="280" y="480" width="200" height="30" as="geometry" />
</mxCell>
<mxCell id="FzdVbH49xBQuPaiEanxh-41" value="<font color="#007fff" style="font-size: 10px;"><font style="font-size: 10px;"><font style="font-size: 10px;"><font style="font-size: 10px;">bridge:&nbsp;桥接方法是由编译器自动生成的方法,主要用于实现泛型类型的类型擦除。这些方法通常用于确保类型安全的多态调用。<br style=""></font>varargs:&nbsp;表示该方法接受可变数量的参数<br style="">strict:&nbsp;表示该方法在浮点计算中遵循 IEEE 754 标准,确保浮点运算的精度和行为一致<br>synthetic: 标记合成元素, 表示该元素是由编译器自动生成的,而不是由源代码直接定义的。这些元素通常用于支持内部类、匿名类等特性。<br></font>mandated:&nbsp;标记强制生成的元素,</font>表示该元素是由编译器根据语言规范强制生成的,而不是由用户显式定义的。例如,桥接方法和合成方法通常也是强制生成的。</font>" style="text;html=1;align=left;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontSize=10;" parent="1" vertex="1">
<mxGeometry x="40" y="570" width="730" height="70" as="geometry" />
</mxCell>
<mxCell id="FzdVbH49xBQuPaiEanxh-44" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.75;entryY=1;entryDx=0;entryDy=0;endArrow=block;endFill=1;" parent="1" source="FzdVbH49xBQuPaiEanxh-42" target="VISHqFL7TcA8I7J5W86J-17" edge="1">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="-240" y="620" />
<mxPoint x="-20" y="620" />
<mxPoint x="-20" y="300" />
<mxPoint x="-140" y="300" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="FzdVbH49xBQuPaiEanxh-42" value="<p style="margin: 4px 0px 0px; text-align: center;"><b>ClassTransformer</b><br style="font-size: 11px;"></p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px;"><br></p><p style="margin: 0px 0px 0px 4px;"><br></p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px;"><font color="#007fff">重要方法:</font></p><p style="margin: 0px 0px 0px 4px;"><font color="#007fff">//设置目标ClassVisitor, 对于 ClassEmitter 是设置输出工具(ClassWriter)</font></p><p style="margin: 0px 0px 0px 4px;"><span style="background-color: initial;">public abstract void <b>setTarget</b>(ClassVisitor var1);</span><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=11;fontFamily=Helvetica;html=1;whiteSpace=wrap;" parent="1" vertex="1">
<mxGeometry x="-440" y="1000" width="400" height="120" as="geometry" />
</mxCell>
<mxCell id="FzdVbH49xBQuPaiEanxh-45" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;endArrow=block;endFill=1;" parent="1" source="FzdVbH49xBQuPaiEanxh-43" target="FzdVbH49xBQuPaiEanxh-42" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="FzdVbH49xBQuPaiEanxh-49" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;endArrow=block;endFill=1;" parent="1" source="FzdVbH49xBQuPaiEanxh-43" target="FzdVbH49xBQuPaiEanxh-48" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="FzdVbH49xBQuPaiEanxh-71" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;endArrow=open;endFill=0;" parent="1" source="FzdVbH49xBQuPaiEanxh-43" target="FzdVbH49xBQuPaiEanxh-70" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="FzdVbH49xBQuPaiEanxh-43" value="<p style="margin: 4px 0px 0px; text-align: center;"><b>ClassEmitter</b><br style="font-size: 11px;"></p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px;"><font color="#007fff"><b>Class 发射器</b>,应该是想表达输出Class的意思, <b>其 emit_xxx方法最终是将字节码片段写入到 ClassWriter</b></font></p><p style="margin: 0px 0px 0px 4px;"><br></p><p style="margin: 0px 0px 0px 4px;"><font color="#007fff">//类字节码信息,这个类没有字段只是提供了几个方法</font></p><p style="margin: 0px 0px 0px 4px;">private <b>ClassInfo</b> classInfo;</p><p style="margin: 0px 0px 0px 4px;">private Map fieldInfo;</p><p style="margin: 0px 0px 0px 4px;"><br></p><p style="margin: 0px 0px 0px 4px;">private static int hookCounter;</p><p style="margin: 0px 0px 0px 4px;">private MethodVisitor rawStaticInit;</p><p style="margin: 0px 0px 0px 4px;">private CodeEmitter staticInit;</p><p style="margin: 0px 0px 0px 4px;">private CodeEmitter staticHook;</p><p style="margin: 0px 0px 0px 4px;">private Signature staticHookSig;</p><p style="margin: 0px 0px 0px 4px;"><br></p><p style="margin: 0px 0px 0px 4px;"><br></p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px;"><br style="font-size: 11px;"></p><p style="margin: 0px 0px 0px 4px;"><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=11;fontFamily=Helvetica;html=1;whiteSpace=wrap;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="-440" y="1240" width="400" height="280" as="geometry" />
</mxCell>
<mxCell id="FzdVbH49xBQuPaiEanxh-48" value="<p style="margin: 4px 0px 0px; text-align: center;"><b>ClassInfo</b><br style="font-size: 11px;"></p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px;"><br></p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px;"><font color="#007fff">重要方法:</font></p><p style="margin: 0px 0px 0px 4px;"><font color="#007fff">// 获取Class类型信息,这里是代理类类型信息</font></p><p style="margin: 0px 0px 0px 4px;">public abstract Type getType();</p><p style="margin: 0px 0px 0px 4px;"><font color="#007fff">// 获取父类信息,这里是被代理的类类型信息</font></p><p style="margin: 0px 0px 0px 4px;"><span style="background-color: initial;">public abstract Type getSuperType();</span><br></p><p style="margin: 0px 0px 0px 4px;"><span style="background-color: initial;"><font color="#007fff">// 类要实现的接口类型信息</font></span></p><p style="margin: 0px 0px 0px 4px;">public abstract Type[] getInterfaces();</p><p style="margin: 0px 0px 0px 4px;"><font color="#007fff">// 类的修饰符</font></p><p style="margin: 0px 0px 0px 4px;"><span style="background-color: initial;">public abstract int getModifiers();</span><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=11;fontFamily=Helvetica;html=1;whiteSpace=wrap;" parent="1" vertex="1">
<mxGeometry x="-880" y="1000" width="400" height="200" as="geometry" />
</mxCell>
<mxCell id="FzdVbH49xBQuPaiEanxh-53" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="FzdVbH49xBQuPaiEanxh-50" target="FzdVbH49xBQuPaiEanxh-52" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="FzdVbH49xBQuPaiEanxh-59" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="FzdVbH49xBQuPaiEanxh-50" target="FzdVbH49xBQuPaiEanxh-58" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="FzdVbH49xBQuPaiEanxh-50" value="<div><font color="#007fff">// 这里 cv 是 DebuggingClassWriter</font></div><div>this.cv.<b>visit</b>(version, access, this.classInfo.getType().getInternalName(), (String)null, this.classInfo.getSuperType().getInternalName(), TypeUtils.toInternalNames(interfaces));</div><div>if (source != null) { <font color="#007fff">// 这个测试中是代理类,source 值是 “&lt;generated&gt;”</font></div><div>&nbsp; &nbsp; this.cv.<b>visitSource</b>(source, (String)null);</div><div>}</div>" style="rounded=1;whiteSpace=wrap;html=1;align=left;fontSize=11;arcSize=8;" parent="1" vertex="1">
<mxGeometry x="1600" y="720" width="440" height="80" as="geometry" />
</mxCell>
<mxCell id="FzdVbH49xBQuPaiEanxh-55" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="FzdVbH49xBQuPaiEanxh-52" target="FzdVbH49xBQuPaiEanxh-54" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="FzdVbH49xBQuPaiEanxh-52" value="<div>this.className = name.replace('/', '.');</div><div>this.superName = superName.replace('/', '.');</div><div><font color="#007fff"><b>// 调用父类(ClassVisitor)的visit方法, 内部调用ClassWriter将这些数据最终写到 ClassWriter</b></font></div><div>super.visit(version, access, name, signature, superName, interfaces);</div>" style="rounded=1;whiteSpace=wrap;html=1;align=left;fontSize=11;arcSize=8;" parent="1" vertex="1">
<mxGeometry x="2080" y="720" width="440" height="80" as="geometry" />
</mxCell>
<mxCell id="FzdVbH49xBQuPaiEanxh-54" value="<div style="font-size: 10px;"><font color="#007fff"><b>// 写class头部信息</b></font></div><div style="font-size: 10px;">public final void <b>visit</b>(</div><div style="font-size: 10px;">&nbsp; &nbsp; final int version,</div><div style="font-size: 10px;">&nbsp; &nbsp; final int access,</div><div style="font-size: 10px;">&nbsp; &nbsp; final String name,</div><div style="font-size: 10px;">&nbsp; &nbsp; final String signature,</div><div style="font-size: 10px;">&nbsp; &nbsp; final String superName,</div><div style="font-size: 10px;">&nbsp; &nbsp; final String[] interfaces) {</div><div style="font-size: 10px;"><br style="font-size: 10px;"></div><div style="font-size: 10px;">&nbsp; &nbsp; this.<b>version</b> = version;</div><div style="font-size: 10px;">&nbsp; &nbsp; this.<b>accessFlags</b> = access;</div><div style="font-size: 10px;">&nbsp; &nbsp; this.thisClass = <b>symbolTable</b>.<b>setMajorVersionAndClassName</b>(version &amp; 0xFFFF, name);</div><div style="font-size: 10px;">&nbsp; &nbsp; if (signature != null) {</div><div style="font-size: 10px;">&nbsp; &nbsp; &nbsp; &nbsp; this.signatureIndex = <b>symbolTable</b>.addConstantUtf8(signature);</div><div style="font-size: 10px;">&nbsp; &nbsp; }</div><div style="font-size: 10px;">&nbsp; &nbsp; this.superClass = superName == null ? 0 : <b>symbolTable</b>.addConstantClass(superName).index;</div><div style="font-size: 10px;">&nbsp; &nbsp; if (interfaces != null &amp;&amp; interfaces.length &gt; 0) {</div><div style="font-size: 10px;">&nbsp; &nbsp; &nbsp; &nbsp; interfaceCount = interfaces.length;</div><div style="font-size: 10px;">&nbsp; &nbsp; &nbsp; &nbsp; this.interfaces = new int[interfaceCount];</div><div style="font-size: 10px;">&nbsp; &nbsp; &nbsp; &nbsp; for (int i = 0; i &lt; interfaceCount; ++i) {</div><div style="font-size: 10px;">&nbsp; &nbsp; &nbsp; &nbsp; this.interfaces[i] = <b>symbolTable</b>.addConstantClass(interfaces[i]).index;</div><div style="font-size: 10px;">&nbsp; &nbsp; &nbsp; &nbsp; }</div><div style="font-size: 10px;">&nbsp; &nbsp; }</div><div style="font-size: 10px;">&nbsp; &nbsp; if (compute == MethodWriter.COMPUTE_MAX_STACK_AND_LOCAL <br>&nbsp; &nbsp; &nbsp; &nbsp; &amp;&amp; (version &amp; 0xFFFF) &gt;= Opcodes.V1_7) {</div><div style="font-size: 10px;">&nbsp; &nbsp; &nbsp; &nbsp; compute = MethodWriter.COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES;</div><div style="font-size: 10px;">&nbsp; &nbsp; }</div><div style="font-size: 10px;">}</div>" style="rounded=1;whiteSpace=wrap;html=1;align=left;fontSize=10;arcSize=1;" parent="1" vertex="1">
<mxGeometry x="2560" y="440" width="440" height="360" as="geometry" />
</mxCell>
<mxCell id="FzdVbH49xBQuPaiEanxh-56" value="<p style="margin: 4px 0px 0px; text-align: center;"><b>SymbolTable</b><br style="font-size: 11px;"></p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px;"><font color="#007fff">符号表,The constant pool entries, the BootstrapMethods attribute entries and the (ASM specific) type table entries of a class.</font></p><p style="margin: 0px 0px 0px 4px;"><br></p><p style="margin: 0px 0px 0px 4px;">final ClassWriter classWriter;</p><p style="margin: 0px 0px 0px 4px;"><br></p><p style="margin: 0px 0px 0px 4px;">private final ClassReader sourceClassReader;</p><p style="margin: 0px 0px 0px 4px;"><font color="#007fff">// 主版本号</font></p><p style="margin: 0px 0px 0px 4px;">private int majorVersion;</p><p style="margin: 0px 0px 0px 4px;"><font color="#007fff">// 类名</font></p><p style="margin: 0px 0px 0px 4px;">private String className;</p><p style="margin: 0px 0px 0px 4px;"><br></p><p style="margin: 0px 0px 0px 4px;">private int entryCount;</p><p style="margin: 0px 0px 0px 4px;"><br></p><p style="margin: 0px 0px 0px 4px;">private Entry[] entries;</p><p style="margin: 0px 0px 0px 4px;"><font color="#007fff">// 常量池中元素数量</font></p><p style="margin: 0px 0px 0px 4px;">private int constantPoolCount;</p><p style="margin: 0px 0px 0px 4px;"><font color="#007fff"><b>// 常量池,ByteVector 就是 byte数组</b></font></p><p style="margin: 0px 0px 0px 4px;">private ByteVector <b>constantPool</b>;</p><p style="margin: 0px 0px 0px 4px;"><br></p><p style="margin: 0px 0px 0px 4px;">private int bootstrapMethodCount;</p><p style="margin: 0px 0px 0px 4px;"><br></p><p style="margin: 0px 0px 0px 4px;">private ByteVector <b>bootstrapMethods</b>;</p><p style="margin: 0px 0px 0px 4px;"><br></p><p style="margin: 0px 0px 0px 4px;">private int typeCount;</p><p style="margin: 0px 0px 0px 4px;"><br></p><p style="margin: 0px 0px 0px 4px;">private Entry[] <b>typeTable</b>;</p><div><br></div><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px;"><font color="#007fff">重要方法:</font></p><p style="margin: 0px 0px 0px 4px;"><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=11;fontFamily=Helvetica;html=1;whiteSpace=wrap;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="-1320" y="320" width="400" height="480" as="geometry" />
</mxCell>
<mxCell id="FzdVbH49xBQuPaiEanxh-58" value="<div>if (file != null) {</div><div>&nbsp; &nbsp; sourceFileIndex = <b>symbolTable</b>.addConstantUtf8(file);</div><div>}</div><div>if (debug != null) {</div><div>&nbsp; &nbsp; debugExtension = new ByteVector().encodeUtf8(debug, 0, Integer.MAX_VALUE);</div><div>}</div>" style="rounded=1;whiteSpace=wrap;html=1;align=left;fontSize=11;arcSize=8;" parent="1" vertex="1">
<mxGeometry x="2080" y="820" width="440" height="80" as="geometry" />
</mxCell>
<mxCell id="FzdVbH49xBQuPaiEanxh-60" value="<div>this.fieldInfo.put(name, info);</div><div>this.cv.<b>visitField</b>(access, name, type.getDescriptor(), (String)null, value);</div>" style="rounded=1;whiteSpace=wrap;html=1;align=left;fontSize=11;arcSize=8;" parent="1" vertex="1">
<mxGeometry x="1600" y="1000" width="440" height="60" as="geometry" />
</mxCell>
<mxCell id="FzdVbH49xBQuPaiEanxh-62" value="<div style="font-size: 11px;"><font color="#007fff" style="font-size: 11px;">callbackTypes = {Type[7]@6791}&nbsp;</font></div><div style="font-size: 11px;"><font color="#007fff" style="font-size: 11px;">&nbsp;0 = {Type@7266} "Lorg/springframework/cglib/proxy/<b>MethodInterceptor</b>;"</font></div><div style="font-size: 11px;"><font color="#007fff" style="font-size: 11px;">&nbsp;1 = {Type@7266} "Lorg/springframework/cglib/proxy/MethodInterceptor;"</font></div><div style="font-size: 11px;"><font color="#007fff" style="font-size: 11px;">&nbsp;2 = {Type@7267} "Lorg/springframework/cglib/proxy/NoOp;"</font></div><div style="font-size: 11px;"><font color="#007fff" style="font-size: 11px;">&nbsp;3 = {Type@7268} "Lorg/springframework/cglib/proxy/Dispatcher;"</font></div><div style="font-size: 11px;"><font color="#007fff" style="font-size: 11px;">&nbsp;4 = {Type@7268} "Lorg/springframework/cglib/proxy/Dispatcher;"</font></div><div style="font-size: 11px;"><font color="#007fff" style="font-size: 11px;">&nbsp;5 = {Type@7266} "Lorg/springframework/cglib/proxy/MethodInterceptor;"</font></div><div style="font-size: 11px;"><font color="#007fff" style="font-size: 11px;">&nbsp;6 = {Type@7266} "Lorg/springframework/cglib/proxy/MethodInterceptor;"</font></div>" style="text;html=1;align=left;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontSize=11;" parent="1" vertex="1">
<mxGeometry x="-2160" y="560" width="390" height="120" as="geometry" />
</mxCell>
<mxCell id="FzdVbH49xBQuPaiEanxh-69" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="FzdVbH49xBQuPaiEanxh-64" target="FzdVbH49xBQuPaiEanxh-68" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="FzdVbH49xBQuPaiEanxh-64" value="CallbackGenerator[] generators = CallbackInfo.getGenerators(callbackTypes);<br><font color="#007fff">// CallbackGenerator -&gt; List&lt;MethodInfo&gt;</font><br>Map groups = new HashMap();<br>...<br><div>Iterator it1 = methods.iterator();</div><div>Iterator it2 = (actualMethods != null) ? actualMethods.iterator() : null;</div><div><font color="#007fff"><b>// 先判断每个方法适合使用哪种 callbackType 增强,进行分组存储到 groups</b></font></div><div><b>while</b> (it1.hasNext()) {<br></div><div></div>&nbsp; &nbsp; MethodInfo method = (MethodInfo) it1.next();<br>&nbsp; &nbsp; Method actualMethod = (it2 != null) ? (Method) it2.next() : null;<br>&nbsp; &nbsp; <font color="#007fff">// 根据 CallbackFilter 判断 actualMethod 应该使用哪种 callbackType 增强</font><br>&nbsp; &nbsp; int index = filter.<b>accept</b>(actualMethod);<br>&nbsp; &nbsp;&nbsp;originalModifiers.put(method, (actualMethod != null ? actualMethod.getModifiers() : method.getModifiers()));<div>&nbsp; &nbsp; indexes.put(method, index);</div><div>&nbsp; &nbsp; List group = (List) groups.get(generators[index]);</div><div>&nbsp; &nbsp; if (group == null) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; groups.put(generators[index], group = new ArrayList(methods.size()));</div><div>&nbsp; &nbsp; }</div><div>&nbsp; &nbsp; <b>group.add(method);</b></div><div>&nbsp; &nbsp; ...</div><div>}</div><div><br></div><div><font color="#007fff"><b>// CodeEmitter 用于将方法的字节码片段输出到 ClassWriter</b></font></div><div>CodeEmitter se = ce.getStaticHook();<br></div><div>CallbackGenerator.Context context = new CallbackGenerator.Context() {...}<br></div><div><br></div><div><b><font color="#007fff">// 执行每一组方法的代理增强重写</font></b></div><div><div>for (int i = 0; i &lt; callbackTypes.length; i++) {</div><div>&nbsp; &nbsp; CallbackGenerator gen = generators[i];</div><div>&nbsp; &nbsp; if (!seenGen.contains(gen)) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; seenGen.add(gen);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; final List <b>fmethods</b> = (List) groups.get(gen);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; if (fmethods != null) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; try {</div><div><font color="#007fff">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // 1&nbsp;</font></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; gen.<b>generate</b>(ce, context, fmethods);</div><div><font color="#007fff">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // 2</font></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; gen.<b>generateStatic</b>(se, context, fmethods);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp;<span style="background-color: initial;">catch (RuntimeException x) {</span></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; throw x;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp;<span style="background-color: initial;">catch (Exception x) {</span></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; throw new CodeGenerationException(x);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; }</div><div>}</div><div>se.return_value();</div><div>se.end_method();</div></div>" style="rounded=1;whiteSpace=wrap;html=1;align=left;fontSize=11;arcSize=2;" parent="1" vertex="1">
<mxGeometry x="1600" y="1120" width="440" height="660" as="geometry" />
</mxCell>
<mxCell id="FzdVbH49xBQuPaiEanxh-68" value="<div>Map <b>sigMap</b> = new HashMap();</div><div>Iterator it = methods.iterator();</div><div>while(it.hasNext()) {</div><div>&nbsp; &nbsp; MethodInfo method = (MethodInfo)it.next();</div><div>&nbsp; &nbsp; Signature sig = method.getSignature();</div><div>&nbsp; &nbsp; Signature impl = context.getImplSignature(method);</div><div>&nbsp; &nbsp; String methodField = this.getMethodField(impl);</div><div>&nbsp; &nbsp; String methodProxyField = this.getMethodProxyField(impl);</div><div>&nbsp; &nbsp; sigMap.put(sig.toString(), methodProxyField);</div><div>&nbsp; &nbsp; ce.declare_field(26, methodField, METHOD, (Object)null);</div><div>&nbsp; &nbsp; ce.declare_field(26, methodProxyField, METHOD_PROXY, (Object)null);</div><div>&nbsp; &nbsp; ce.declare_field(26, "CGLIB$emptyArgs", Constants.TYPE_OBJECT_ARRAY, (Object)null);</div><div>&nbsp; &nbsp; <b>CodeEmitter</b> <b>e</b> = ce.begin_method(16, impl, method.getExceptionTypes());</div><div>&nbsp; &nbsp; superHelper(e, method, context);</div><div>&nbsp; &nbsp; e.return_value();</div><div>&nbsp; &nbsp; e.end_method();</div><div>&nbsp; &nbsp; e = context.<b>beginMethod</b>(ce, method);</div><div>&nbsp; &nbsp; Label nullInterceptor = e.make_label();</div><div>&nbsp; &nbsp; context.emitCallback(e, context.getIndex(method));</div><div>&nbsp; &nbsp; e.dup();</div><div>&nbsp; &nbsp; e.ifnull(nullInterceptor);</div><div>&nbsp; &nbsp; e.load_this();</div><div>&nbsp; &nbsp; e.getfield(methodField);</div><div>&nbsp; &nbsp; if (sig.getArgumentTypes().length == 0) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; e.getfield("CGLIB$emptyArgs");</div><div>&nbsp; &nbsp; } else {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; e.create_arg_array();</div><div>&nbsp; &nbsp; }</div><div><br></div><div>&nbsp; &nbsp; e.getfield(methodProxyField);</div><div>&nbsp; &nbsp; e.<b>invoke_interface</b>(METHOD_INTERCEPTOR, INTERCEPT);</div><div>&nbsp; &nbsp; e.unbox_or_zero(sig.getReturnType());</div><div>&nbsp; &nbsp; e.return_value();</div><div>&nbsp; &nbsp; e.mark(nullInterceptor);</div><div>&nbsp; &nbsp; superHelper(e, method, context);</div><div>&nbsp; &nbsp; e.return_value();</div><div>&nbsp; &nbsp; e.end_method();</div><div>}</div><div><br></div><div>this.<b>generateFindProxy</b>(ce, sigMap);</div>" style="rounded=1;whiteSpace=wrap;html=1;align=left;fontSize=11;arcSize=2;" parent="1" vertex="1">
<mxGeometry x="2080" y="1120" width="440" height="560" as="geometry" />
</mxCell>
<mxCell id="FzdVbH49xBQuPaiEanxh-73" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;endArrow=block;endFill=1;" parent="1" source="FzdVbH49xBQuPaiEanxh-70" target="FzdVbH49xBQuPaiEanxh-72" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="FzdVbH49xBQuPaiEanxh-70" value="<p style="margin: 4px 0px 0px; text-align: center;"><b>CodeEmitter</b><br style="font-size: 11px;"></p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px;"><font color="#007fff"><b>Code 发射器,其 emit_xxx 方法用于将方法的字节码片段最终输出到 ClassWriter</b></font></p><p style="margin: 0px 0px 0px 4px;"><span style="background-color: initial;"><br></span></p><p style="margin: 0px 0px 0px 4px;"><span style="background-color: initial;">private ClassEmitter ce;</span><br></p><p style="margin: 0px 0px 0px 4px;">private State state;</p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px;"><br style="font-size: 11px;"></p><p style="margin: 0px 0px 0px 4px;"><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=11;fontFamily=Helvetica;html=1;whiteSpace=wrap;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="-1320" y="1240" width="400" height="280" as="geometry" />
</mxCell>
<mxCell id="FzdVbH49xBQuPaiEanxh-72" value="<p style="margin: 4px 0px 0px; text-align: center;"><b>LocalVariablesSorter&nbsp;</b><span style="background-color: initial;">extends MethodVisitor</span></p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px;"><br></p><p style="margin: 0px 0px 0px 4px;">protected final int firstLocal;</p><p style="margin: 0px 0px 0px 4px;">private final State state;</p><hr style="font-size: 11px;"><p style="margin: 0px 0px 0px 4px;"><br style="font-size: 11px;"></p><p style="margin: 0px 0px 0px 4px;"><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=11;fontFamily=Helvetica;html=1;whiteSpace=wrap;" parent="1" vertex="1">
<mxGeometry x="-1320" y="1040" width="400" height="160" as="geometry" />
</mxCell>
<mxCell id="10TpCgqnUDmNamHutM36-1" value="<div><b>代理类生成后,ClassWriter 内部数据结构:</b></div><div><font color="#007fff"><br></font></div><div><font color="#007fff">cw = {<b>DebuggingClassWriter</b>@7008}&nbsp;</font></div><div><font color="#007fff">&nbsp;className = "top.kwseeker.labs.spring.transaction.service.TransferService$$EnhancerBySpringCGLIB$$d125a991"</font></div><div><font color="#007fff">&nbsp;superName = "top.kwseeker.labs.spring.transaction.service.TransferService"</font></div><div><font color="#007fff">&nbsp;api = 589824</font></div><div><font color="#007fff">&nbsp;cv = {<b>ClassWriter</b>@7027}&nbsp;</font></div><div><font color="#007fff">&nbsp; flags = 2</font></div><div><font color="#007fff">&nbsp; version = 52</font></div><div><font color="#007fff">&nbsp; <b>symbolTable</b> = {SymbolTable@7031}&nbsp;</font></div><div><font color="#007fff">&nbsp; accessFlags = 1</font></div><div><font color="#007fff">&nbsp; thisClass = 2</font></div><div><font color="#007fff">&nbsp; superClass = 4</font></div><div><font color="#007fff">&nbsp; interfaceCount = 3</font></div><div><font color="#007fff">&nbsp; <b>interfaces</b> = {int[3]@7087} [6, 8, 10]</font></div><div><font color="#007fff">&nbsp; <b>firstField</b> = {FieldWriter@7088}&nbsp;</font></div><div><font color="#007fff">&nbsp; <b>lastField</b> = {FieldWriter@7089}&nbsp;</font></div><div><font color="#007fff">&nbsp; <b>firstMethod</b> = {MethodWriter@7090}&nbsp;</font></div><div><font color="#007fff">&nbsp; <b>lastMethod</b> = {MethodWriter@7091}&nbsp;</font></div><div><font color="#007fff">&nbsp; numberOfInnerClasses = 0</font></div><div><font color="#007fff">&nbsp; <b>innerClasses</b> = null</font></div><div><font color="#007fff">&nbsp; enclosingClassIndex = 0</font></div><div><font color="#007fff">&nbsp; enclosingMethodIndex = 0</font></div><div><font color="#007fff">&nbsp; signatureIndex = 0</font></div><div><font color="#007fff">&nbsp; sourceFileIndex = 11</font></div><div><font color="#007fff">&nbsp; debugExtension = null</font></div><div><font color="#007fff">&nbsp; <b>lastRuntimeVisibleAnnotation</b> = null</font></div><div><font color="#007fff">&nbsp; <b>lastRuntimeInvisibleAnnotation</b> = null</font></div><div><font color="#007fff">&nbsp; lastRuntimeVisibleTypeAnnotation = null</font></div><div><font color="#007fff">&nbsp; lastRuntimeInvisibleTypeAnnotation = null</font></div><div><font color="#007fff">&nbsp; moduleWriter = null</font></div><div><font color="#007fff">&nbsp; nestHostClassIndex = 0</font></div><div><font color="#007fff">&nbsp; numberOfNestMemberClasses = 0</font></div><div><font color="#007fff">&nbsp; <b>nestMemberClasses</b> = null</font></div><div><font color="#007fff">&nbsp; numberOfPermittedSubclasses = 0</font></div><div><font color="#007fff">&nbsp; permittedSubclasses = null</font></div><div><font color="#007fff">&nbsp; firstRecordComponent = null</font></div><div><font color="#007fff">&nbsp; lastRecordComponent = null</font></div><div><font color="#007fff">&nbsp; firstAttribute = null</font></div><div><font color="#007fff">&nbsp; compute = 4</font></div><div><font color="#007fff">&nbsp; api = 589824</font></div><div><font color="#007fff">&nbsp; cv = null</font></div>" style="text;html=1;align=left;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" vertex="1" parent="1">
<mxGeometry x="40" y="660" width="650" height="620" as="geometry" />
</mxCell>
<mxCell id="10TpCgqnUDmNamHutM36-2" value="<div>return (byte[])((byte[])AccessController.doPrivileged(new PrivilegedAction() {</div><div>&nbsp; &nbsp; public Object run() {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; byte[] b = ((ClassWriter)DebuggingClassWriter.access$001(DebuggingClassWriter.this)).toByteArray();</div><div><font color="#007fff"><b>&nbsp; &nbsp; &nbsp; &nbsp; // debugLocation 不为 null 就在 debugLocation 指定的路径下打印 .class 文件</b></font></div><div><b>&nbsp; &nbsp; &nbsp; &nbsp; if (DebuggingClassWriter.debugLocation != null) {</b></div><div><b><font color="#007fff">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // 类的全限定名路径</font></b></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; String dirs = DebuggingClassWriter.this.className.replace('.', File.separatorChar);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; try {</div><div><b><font color="#007fff">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // 文件路径: debugLocaltion + 全限定名路径 + .class</font></b></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (new File(DebuggingClassWriter.debugLocation + File.separatorChar + dirs)).getParentFile().mkdirs();</div><div><b>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; File file = new File(new File(DebuggingClassWriter.debugLocation), dirs + ".class");</b></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; OutputStream out = new BufferedOutputStream(new FileOutputStream(file));</div><div><br></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; try {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; out.write(b);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } finally {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; out.close();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div><font color="#007fff"><b><span style=""><span style="white-space: pre;">&nbsp;&nbsp;&nbsp;&nbsp;</span></span><span style=""><span style="white-space: pre;">&nbsp;&nbsp;&nbsp; &nbsp;</span></span>// 还支持打印 .asm</b></font></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (<b>DebuggingClassWriter.traceCtor </b>!= null) {</div><div>&nbsp; &nbsp;&nbsp;<b style="background-color: initial; border-color: var(--border-color);"><font style="border-color: var(--border-color);" color="#007fff">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // 文件路径: debugLocaltion + 全限定名路径 + .asm</font></b></div><div><b>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; file = new File(new File(DebuggingClassWriter.debugLocation), dirs + ".asm");</b></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; out = new BufferedOutputStream(new FileOutputStream(file));</div><div><br></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; try {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ClassReader cr = new ClassReader(b);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PrintWriter pw = new PrintWriter(new OutputStreamWriter(out));</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ClassVisitor tcv = (ClassVisitor)DebuggingClassWriter.traceCtor.newInstance(null, pw);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cr.accept(tcv, 0);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; pw.flush();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } finally {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; out.close();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } catch (Exception var17) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; throw new CodeGenerationException(var17);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div><br></div><div>&nbsp; &nbsp; &nbsp; &nbsp; return b;</div><div>&nbsp; &nbsp; }</div><div>}));</div>" style="rounded=1;whiteSpace=wrap;html=1;align=left;fontSize=11;fillColor=#dae8fc;strokeColor=#6c8ebf;arcSize=1;" vertex="1" parent="1">
<mxGeometry x="1000" y="1800" width="560" height="560" as="geometry" />
</mxCell>
<mxCell id="10TpCgqnUDmNamHutM36-4" value="<b>注意</b>:<br>1 Spring 官方已经支持<b>查看生成的动态代理 .class 文件</b>,只需要设置系统属性 "<b>cglib.debugLocation</b>"<br><font color="#007fff">&nbsp; &nbsp;比如: "-Dcglib.debugLocation=/tmp/spring-cglib"</font>" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=top;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
<mxGeometry x="840" y="10" width="560" height="130" as="geometry" />
</mxCell>
<mxCell id="10TpCgqnUDmNamHutM36-6" value="<font color="#007fff">对 Class 内部还包括一些 FieldVisitor MethodVisitor 等,<br>分别用于构建字段、方法的字节码<br></font>" style="text;html=1;align=left;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" vertex="1" parent="1">
<mxGeometry x="-760" y="80" width="320" height="40" as="geometry" />
</mxCell>
<mxCell id="10TpCgqnUDmNamHutM36-7" value="<div>/tmp/spring-cglib</div><div>└── top</div><div>&nbsp; &nbsp; └── kwseeker</div><div>&nbsp; &nbsp; &nbsp; &nbsp; └── labs</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; └── spring</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; └── transaction</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ├── service</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ├── TransferService$$EnhancerBySpringCGLIB$$bc002a25$$FastClassBySpringCGLIB$$344f828.class</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ├── <b>TransferService$$EnhancerBySpringCGLIB$$bc002a25.class</b></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; └── TransferService$$FastClassBySpringCGLIB$$1b385304.class</div><div><font color="#007fff">上面两个 <b>Fast</b> 代理类是经过 CgLib 优化的代理类,使用索引而不是反射来调用方法提升性能。</font></div><div><font color="#007fff">但是调试可以发现默认基本还是使用的非 Fast 代理类。TODO why?</font></div><div><br></div>" style="text;html=1;align=left;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" vertex="1" parent="1">
<mxGeometry x="1580" y="1820" width="670" height="200" as="geometry" />
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>