Groovy深入探索——DGM調(diào)用優(yōu)化
DGM調(diào)用優(yōu)化是通過(guò)直接調(diào)用代替反射調(diào)用的方式來(lái)提高DGM方法的調(diào)用效率。
注:以下分析的Groovy源代碼來(lái)自Groovy 1.8.0 rc4。
DGM
DGM其實(shí)是Groovy社區(qū)對(duì)DefaultGroovyMethods的簡(jiǎn)稱,完整類名是org.codehaus.groovy.runtime.DefaultGroovyMethods。
DefaultGroovyMethods類中包含了Groovy為JDK的類添加的各種方法,如
反射調(diào)用和直接調(diào)用
在Groovy中,用于表示一個(gè)方法的是一個(gè)MetaMethod(這是一個(gè)抽象類)實(shí)例,MetaMethod類似于JDK中的Method。而在大多數(shù)情況下,這個(gè)表示方法的實(shí)例會(huì)是CachedMethod(MetaMethod的派生類)類型的。調(diào)用其代表的方法時(shí),會(huì)調(diào)用CachedMethod的invoke方法,其代碼如下
可見(jiàn),在Groovy中一般是通過(guò)反射的方式調(diào)用方法的。
眾所周知,在Java中,通過(guò)反射來(lái)調(diào)用方法,比直接調(diào)用方法會(huì)慢上幾倍。因此,DGM調(diào)用優(yōu)化的思想就是通過(guò)直接調(diào)用來(lái)代替反射調(diào)用。而要實(shí)現(xiàn)直接調(diào)用,則需要為DGM中的每個(gè)方法生成一個(gè)從MetaMethod派生的包裝類,該類的invoke方法將直接調(diào)用DGM中對(duì)應(yīng)的方法。
DGM調(diào)用優(yōu)化
DGM調(diào)用優(yōu)化的大體流程是這樣的:
1. 在編譯Groovy自身的Java代碼(不是用Groovy寫(xiě)的代碼)之后,通過(guò)調(diào)用DgmConverter類的main方法,為DefaultGroovyMethods的每個(gè)方法生成一個(gè)包裝類,該類繼承GeneratedMetaMethod類,而GeneratedMetaMethod類則繼承MetaMethod類。該包裝類的類名類似于org.codehaus.groovy.runtime.dgm$123($后跟一個(gè)數(shù)),在Groovy分發(fā)的jar包中可以找到總共918個(gè)這樣的類,說(shuō)明DGM中總共有918個(gè)方法。這些包裝類的代碼形式如下(以上面提到的each方法的包裝類為例):
2. 通過(guò)調(diào)用GeneratedMetaMethod.DgmMethodRecord.saveDgmInfo方法,將哪個(gè)DGM方法對(duì)應(yīng)哪個(gè)包裝類的信息寫(xiě)入META-INF/dgminfo文件中
3. 當(dāng)運(yùn)行Groovy程序的時(shí)候,在MetaClassRegistryImpl的實(shí)例初始化時(shí),通過(guò)調(diào)用GeneratedMetaMethod.DgmMethodRecord.loadDgmInfo方法,從META-INF/dgminfo文件中讀取上一步寫(xiě)入的信息。然后為所有包裝類創(chuàng)建GeneratedMetaMethod.Proxy實(shí)例作為其代理
4. 在Groovy程序第一次調(diào)用DGM方法時(shí),則由GeneratedMetaMethod.Proxy實(shí)例載入對(duì)應(yīng)的包裝類并實(shí)例化,然后調(diào)用其invoke方法。這樣就實(shí)現(xiàn)了包裝類的延遲加載,在一定程度上加快了程序初始化加載的速度
那為什么不為用戶寫(xiě)的Groovy程序的每一個(gè)方法,在運(yùn)行時(shí)動(dòng)態(tài)的創(chuàng)建這樣直接調(diào)用的包裝類,來(lái)提高每個(gè)方法的調(diào)用效率呢?那是因?yàn)檫@樣會(huì)產(chǎn)生大量的類,由于每個(gè)類都是需要占用內(nèi)存的,所以會(huì)對(duì)JVM用于存放類信息的PermGen內(nèi)存區(qū)域造成壓力,容易產(chǎn)生OutOfMemoryError。而DGM方法是Groovy程序中大量被調(diào)用的方法(即熱點(diǎn)),而且數(shù)量只有不到1000個(gè),因此適合為其生成包裝類。
代碼分析
先來(lái)看看DgmConverter是如何為DGM方法生成包裝類的:
我們?cè)賮?lái)看看用于創(chuàng)建包裝類的invoke方法的createInvokeMethod方法:
MetaClassRegistryImpl在初始化的時(shí)候,會(huì)調(diào)用自身的registerMethods方法來(lái)從META-INF/dgminfo文件中讀取DGM方法和包裝類的對(duì)應(yīng)關(guān)系:
最后來(lái)看看GeneratedMetaMethod.Proxy如何實(shí)現(xiàn)延遲加載包裝類:
以上分析有不當(dāng)之處敬請(qǐng)指出,謝謝大家的閱讀。
注:以下分析的Groovy源代碼來(lái)自Groovy 1.8.0 rc4。
DGM
DGM其實(shí)是Groovy社區(qū)對(duì)DefaultGroovyMethods的簡(jiǎn)稱,完整類名是org.codehaus.groovy.runtime.DefaultGroovyMethods。
DefaultGroovyMethods類中包含了Groovy為JDK的類添加的各種方法,如
[1, 2, 3].each { println it }
中的each方法就是Groovy為Object類添加的方法,用于遍歷對(duì)象中的所有元素。在Object類的實(shí)例上調(diào)用each方法,其實(shí)調(diào)用的是DefaultGroovyMethods類中的public static <T> T each(T self, Closure closure)
反射調(diào)用和直接調(diào)用
在Groovy中,用于表示一個(gè)方法的是一個(gè)MetaMethod(這是一個(gè)抽象類)實(shí)例,MetaMethod類似于JDK中的Method。而在大多數(shù)情況下,這個(gè)表示方法的實(shí)例會(huì)是CachedMethod(MetaMethod的派生類)類型的。調(diào)用其代表的方法時(shí),會(huì)調(diào)用CachedMethod的invoke方法,其代碼如下
1 public final Object invoke(Object object, Object[] arguments) {
2 try {
3 return cachedMethod.invoke(object, arguments); // cachedMethod的類型是Method
4 } catch (IllegalArgumentException e) {
5 throw new InvokerInvocationException(e);
6 } catch (IllegalAccessException e) {
7 throw new InvokerInvocationException(e);
8 } catch (InvocationTargetException e) {
9 Throwable cause = e.getCause();
10 throw (cause instanceof RuntimeException && !(cause instanceof MissingMethodException)) ? (RuntimeException) cause : new InvokerInvocationException(e);
11 }
12 }
2 try {
3 return cachedMethod.invoke(object, arguments); // cachedMethod的類型是Method
4 } catch (IllegalArgumentException e) {
5 throw new InvokerInvocationException(e);
6 } catch (IllegalAccessException e) {
7 throw new InvokerInvocationException(e);
8 } catch (InvocationTargetException e) {
9 Throwable cause = e.getCause();
10 throw (cause instanceof RuntimeException && !(cause instanceof MissingMethodException)) ? (RuntimeException) cause : new InvokerInvocationException(e);
11 }
12 }
可見(jiàn),在Groovy中一般是通過(guò)反射的方式調(diào)用方法的。
眾所周知,在Java中,通過(guò)反射來(lái)調(diào)用方法,比直接調(diào)用方法會(huì)慢上幾倍。因此,DGM調(diào)用優(yōu)化的思想就是通過(guò)直接調(diào)用來(lái)代替反射調(diào)用。而要實(shí)現(xiàn)直接調(diào)用,則需要為DGM中的每個(gè)方法生成一個(gè)從MetaMethod派生的包裝類,該類的invoke方法將直接調(diào)用DGM中對(duì)應(yīng)的方法。
DGM調(diào)用優(yōu)化
DGM調(diào)用優(yōu)化的大體流程是這樣的:
1. 在編譯Groovy自身的Java代碼(不是用Groovy寫(xiě)的代碼)之后,通過(guò)調(diào)用DgmConverter類的main方法,為DefaultGroovyMethods的每個(gè)方法生成一個(gè)包裝類,該類繼承GeneratedMetaMethod類,而GeneratedMetaMethod類則繼承MetaMethod類。該包裝類的類名類似于org.codehaus.groovy.runtime.dgm$123($后跟一個(gè)數(shù)),在Groovy分發(fā)的jar包中可以找到總共918個(gè)這樣的類,說(shuō)明DGM中總共有918個(gè)方法。這些包裝類的代碼形式如下(以上面提到的each方法的包裝類為例):
1 public class dgm$123 extends GeneratedMetaMethod {
2
3 public Object invoke(Object object, Object[] arguments) {
4 return DefaultGroovyMethods.each((Object) object, (Closure) arguments[0]); // 將各參數(shù)強(qiáng)制轉(zhuǎn)換為對(duì)應(yīng)的類型后,直接調(diào)用DefaultGroovyMethods中對(duì)應(yīng)的方法
5 }
6
7 }
2

3 public Object invoke(Object object, Object[] arguments) {
4 return DefaultGroovyMethods.each((Object) object, (Closure) arguments[0]); // 將各參數(shù)強(qiáng)制轉(zhuǎn)換為對(duì)應(yīng)的類型后,直接調(diào)用DefaultGroovyMethods中對(duì)應(yīng)的方法
5 }
6

7 }
2. 通過(guò)調(diào)用GeneratedMetaMethod.DgmMethodRecord.saveDgmInfo方法,將哪個(gè)DGM方法對(duì)應(yīng)哪個(gè)包裝類的信息寫(xiě)入META-INF/dgminfo文件中
3. 當(dāng)運(yùn)行Groovy程序的時(shí)候,在MetaClassRegistryImpl的實(shí)例初始化時(shí),通過(guò)調(diào)用GeneratedMetaMethod.DgmMethodRecord.loadDgmInfo方法,從META-INF/dgminfo文件中讀取上一步寫(xiě)入的信息。然后為所有包裝類創(chuàng)建GeneratedMetaMethod.Proxy實(shí)例作為其代理
4. 在Groovy程序第一次調(diào)用DGM方法時(shí),則由GeneratedMetaMethod.Proxy實(shí)例載入對(duì)應(yīng)的包裝類并實(shí)例化,然后調(diào)用其invoke方法。這樣就實(shí)現(xiàn)了包裝類的延遲加載,在一定程度上加快了程序初始化加載的速度
那為什么不為用戶寫(xiě)的Groovy程序的每一個(gè)方法,在運(yùn)行時(shí)動(dòng)態(tài)的創(chuàng)建這樣直接調(diào)用的包裝類,來(lái)提高每個(gè)方法的調(diào)用效率呢?那是因?yàn)檫@樣會(huì)產(chǎn)生大量的類,由于每個(gè)類都是需要占用內(nèi)存的,所以會(huì)對(duì)JVM用于存放類信息的PermGen內(nèi)存區(qū)域造成壓力,容易產(chǎn)生OutOfMemoryError。而DGM方法是Groovy程序中大量被調(diào)用的方法(即熱點(diǎn)),而且數(shù)量只有不到1000個(gè),因此適合為其生成包裝類。
代碼分析
先來(lái)看看DgmConverter是如何為DGM方法生成包裝類的:
1 public static void main(String[] args) throws IOException, ClassNotFoundException {
2 Class [] classes = new Class [] { // DGM方法事實(shí)上是分別位于這幾個(gè)類中,而不只是在DefaultGroovyMethods類中
3 DefaultGroovyMethods.class,
4 SwingGroovyMethods.class,
5 SqlGroovyMethods.class,
6 XmlGroovyMethods.class,
7 EncodingGroovyMethods.class,
8 DateGroovyMethods.class,
9 ProcessGroovyMethods.class
10 };
11
12 List<CachedMethod> cachedMethodsList = new ArrayList<CachedMethod> ();
13 for (Class aClass : classes) {
14 Collections.addAll(cachedMethodsList, ReflectionCache.getCachedClass(aClass).getMethods()); // 獲取這些類中的所有方法
15 }
16 final CachedMethod[] cachedMethods = cachedMethodsList.toArray(new CachedMethod[cachedMethodsList.size()]);
17
18 List<GeneratedMetaMethod.DgmMethodRecord> records = new ArrayList<GeneratedMetaMethod.DgmMethodRecord> ();
19 for (int i = 0, cur = 0; i < cachedMethods.length; i++) {
20 CachedMethod method = cachedMethods[i];
21 if (!method.isStatic() || !method.isPublic()) // DGM方法必須是static和public的
22 continue;
23 if (method.getCachedMethod().getAnnotation(Deprecated.class) != null) // 已過(guò)時(shí)的DGM方法不處理
24 continue;
25 if (method.getParameterTypes().length == 0) // DGM方法的第一個(gè)參數(shù)表示該方法應(yīng)添加到哪個(gè)類上,因此DGM方法至少有一個(gè)參數(shù)
26 continue;
27
28 final Class returnType = method.getReturnType();
29 final String className = "org/codehaus/groovy/runtime/dgm$" + cur;
30
31 // record記錄著DGM方法和包裝類的對(duì)應(yīng)關(guān)系
32 GeneratedMetaMethod.DgmMethodRecord record = new GeneratedMetaMethod.DgmMethodRecord();
33 records.add(record);
34 record.methodName = method.getName();
35 record.returnType = method.getReturnType();
36 record.parameters = method.getNativeParameterTypes();
37 record.className = className;
38
39 // 創(chuàng)建一個(gè)繼承GeneratedMetaMethod的包裝類
40 ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
41 cw.visit(V1_3,ACC_PUBLIC, className,null,"org/codehaus/groovy/reflection/GeneratedMetaMethod", null);
42 createConstructor(cw);
43 final String methodDescriptor = BytecodeHelper.getMethodDescriptor(returnType, method.getNativeParameterTypes());
44 createInvokeMethod(method, cw, returnType, methodDescriptor); // 我們只關(guān)注invoke方法的生成
45 createDoMethodInvokeMethod(method, cw, className, returnType, methodDescriptor);
46 createIsValidMethodMethod(method, cw, className);
47 cw.visitEnd();
48
49 // 將包裝類寫(xiě)入class文件
50 final byte[] bytes = cw.toByteArray();
51 final FileOutputStream fileOutputStream = new FileOutputStream("target/classes/" + className + ".class");
52 fileOutputStream.write(bytes);
53 fileOutputStream.flush();
54 fileOutputStream.close();
55
56 cur++;
57 }
58
59 GeneratedMetaMethod.DgmMethodRecord.saveDgmInfo (records, "target/classes/META-INF/dgminfo"); // 將DGM方法和包裝類的對(duì)應(yīng)關(guān)系寫(xiě)入META-INF/dgminfo文件
60 }
2 Class [] classes = new Class [] { // DGM方法事實(shí)上是分別位于這幾個(gè)類中,而不只是在DefaultGroovyMethods類中
3 DefaultGroovyMethods.class,
4 SwingGroovyMethods.class,
5 SqlGroovyMethods.class,
6 XmlGroovyMethods.class,
7 EncodingGroovyMethods.class,
8 DateGroovyMethods.class,
9 ProcessGroovyMethods.class
10 };
11
12 List<CachedMethod> cachedMethodsList = new ArrayList<CachedMethod> ();
13 for (Class aClass : classes) {
14 Collections.addAll(cachedMethodsList, ReflectionCache.getCachedClass(aClass).getMethods()); // 獲取這些類中的所有方法
15 }
16 final CachedMethod[] cachedMethods = cachedMethodsList.toArray(new CachedMethod[cachedMethodsList.size()]);
17
18 List<GeneratedMetaMethod.DgmMethodRecord> records = new ArrayList<GeneratedMetaMethod.DgmMethodRecord> ();
19 for (int i = 0, cur = 0; i < cachedMethods.length; i++) {
20 CachedMethod method = cachedMethods[i];
21 if (!method.isStatic() || !method.isPublic()) // DGM方法必須是static和public的
22 continue;
23 if (method.getCachedMethod().getAnnotation(Deprecated.class) != null) // 已過(guò)時(shí)的DGM方法不處理
24 continue;
25 if (method.getParameterTypes().length == 0) // DGM方法的第一個(gè)參數(shù)表示該方法應(yīng)添加到哪個(gè)類上,因此DGM方法至少有一個(gè)參數(shù)
26 continue;
27
28 final Class returnType = method.getReturnType();
29 final String className = "org/codehaus/groovy/runtime/dgm$" + cur;
30
31 // record記錄著DGM方法和包裝類的對(duì)應(yīng)關(guān)系
32 GeneratedMetaMethod.DgmMethodRecord record = new GeneratedMetaMethod.DgmMethodRecord();
33 records.add(record);
34 record.methodName = method.getName();
35 record.returnType = method.getReturnType();
36 record.parameters = method.getNativeParameterTypes();
37 record.className = className;
38
39 // 創(chuàng)建一個(gè)繼承GeneratedMetaMethod的包裝類
40 ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
41 cw.visit(V1_3,ACC_PUBLIC, className,null,"org/codehaus/groovy/reflection/GeneratedMetaMethod", null);
42 createConstructor(cw);
43 final String methodDescriptor = BytecodeHelper.getMethodDescriptor(returnType, method.getNativeParameterTypes());
44 createInvokeMethod(method, cw, returnType, methodDescriptor); // 我們只關(guān)注invoke方法的生成
45 createDoMethodInvokeMethod(method, cw, className, returnType, methodDescriptor);
46 createIsValidMethodMethod(method, cw, className);
47 cw.visitEnd();
48
49 // 將包裝類寫(xiě)入class文件
50 final byte[] bytes = cw.toByteArray();
51 final FileOutputStream fileOutputStream = new FileOutputStream("target/classes/" + className + ".class");
52 fileOutputStream.write(bytes);
53 fileOutputStream.flush();
54 fileOutputStream.close();
55
56 cur++;
57 }
58
59 GeneratedMetaMethod.DgmMethodRecord.saveDgmInfo (records, "target/classes/META-INF/dgminfo"); // 將DGM方法和包裝類的對(duì)應(yīng)關(guān)系寫(xiě)入META-INF/dgminfo文件
60 }
我們?cè)賮?lái)看看用于創(chuàng)建包裝類的invoke方法的createInvokeMethod方法:
1 private static void createInvokeMethod(CachedMethod method, ClassWriter cw, Class returnType, String methodDescriptor) {
2 MethodVisitor mv;
3 mv = cw.visitMethod(ACC_PUBLIC, "invoke", "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", null, null); // 創(chuàng)建一個(gè)public Object invoke(Object object, Object[] arguments)方法
4 mv.visitCode();
5 mv.visitVarInsn(ALOAD,1);
6 BytecodeHelper.doCast(mv, method.getParameterTypes()[0].getTheClass()); // 將調(diào)用者強(qiáng)制轉(zhuǎn)換為DGM方法第一個(gè)參數(shù)的類型
7 loadParameters(method,2,mv);
8 mv.visitMethodInsn(INVOKESTATIC, BytecodeHelper.getClassInternalName(method.getDeclaringClass().getTheClass()), method.getName(), methodDescriptor); // 通過(guò)invokestatic指令直接調(diào)用DGM方法
9 BytecodeHelper.box(mv, returnType);
10 if (method.getReturnType() == void.class) {
11 mv.visitInsn(ACONST_NULL);
12 }
13 mv.visitInsn(ARETURN); // 返回值
14 mv.visitMaxs(0, 0);
15 mv.visitEnd();
16 }
17
18 protected static void loadParameters(CachedMethod method, int argumentIndex, MethodVisitor mv) {
19 CachedClass[] parameters = method.getParameterTypes();
20 int size = parameters.length-1;
21 for (int i = 0; i < size; i++) {
22 mv.visitVarInsn(ALOAD, argumentIndex);
23 BytecodeHelper.pushConstant(mv, i);
24 mv.visitInsn(AALOAD);
25 Class type = parameters[i+1].getTheClass();
26 BytecodeHelper.doCast(mv, type); // 將第i個(gè)參數(shù)強(qiáng)制轉(zhuǎn)換為DGM方法中第i+1個(gè)參數(shù)的類型
27 }
28 }
2 MethodVisitor mv;
3 mv = cw.visitMethod(ACC_PUBLIC, "invoke", "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", null, null); // 創(chuàng)建一個(gè)public Object invoke(Object object, Object[] arguments)方法
4 mv.visitCode();
5 mv.visitVarInsn(ALOAD,1);
6 BytecodeHelper.doCast(mv, method.getParameterTypes()[0].getTheClass()); // 將調(diào)用者強(qiáng)制轉(zhuǎn)換為DGM方法第一個(gè)參數(shù)的類型
7 loadParameters(method,2,mv);
8 mv.visitMethodInsn(INVOKESTATIC, BytecodeHelper.getClassInternalName(method.getDeclaringClass().getTheClass()), method.getName(), methodDescriptor); // 通過(guò)invokestatic指令直接調(diào)用DGM方法
9 BytecodeHelper.box(mv, returnType);
10 if (method.getReturnType() == void.class) {
11 mv.visitInsn(ACONST_NULL);
12 }
13 mv.visitInsn(ARETURN); // 返回值
14 mv.visitMaxs(0, 0);
15 mv.visitEnd();
16 }
17
18 protected static void loadParameters(CachedMethod method, int argumentIndex, MethodVisitor mv) {
19 CachedClass[] parameters = method.getParameterTypes();
20 int size = parameters.length-1;
21 for (int i = 0; i < size; i++) {
22 mv.visitVarInsn(ALOAD, argumentIndex);
23 BytecodeHelper.pushConstant(mv, i);
24 mv.visitInsn(AALOAD);
25 Class type = parameters[i+1].getTheClass();
26 BytecodeHelper.doCast(mv, type); // 將第i個(gè)參數(shù)強(qiáng)制轉(zhuǎn)換為DGM方法中第i+1個(gè)參數(shù)的類型
27 }
28 }
MetaClassRegistryImpl在初始化的時(shí)候,會(huì)調(diào)用自身的registerMethods方法來(lái)從META-INF/dgminfo文件中讀取DGM方法和包裝類的對(duì)應(yīng)關(guān)系:
1 private void registerMethods(final Class theClass, final boolean useMethodWrapper, final boolean useInstanceMethods, Map<CachedClass, List<MetaMethod>> map) {
2 if (useMethodWrapper) { // 我們只看useMethodWrapper為true的情況
3 try {
4 List<GeneratedMetaMethod.DgmMethodRecord> records = GeneratedMetaMethod.DgmMethodRecord.loadDgmInfo(); // 從META-INF/dgminfo文件中讀取DGM方法和包裝類的對(duì)應(yīng)關(guān)系
5
6 for (GeneratedMetaMethod.DgmMethodRecord record : records) {
7 Class[] newParams = new Class[record.parameters.length - 1];
8 System.arraycopy(record.parameters, 1, newParams, 0, record.parameters.length-1);
9
10 MetaMethod method = new GeneratedMetaMethod.Proxy(
11 record.className,
12 record.methodName,
13 ReflectionCache.getCachedClass(record.parameters[0]),
14 record.returnType,
15 newParams
16 ); // 為包裝類創(chuàng)建GeneratedMetaMethod.Proxy代理
17 final CachedClass declClass = method.getDeclaringClass();
18 List<MetaMethod> arr = map.get(declClass);
19 if (arr == null) {
20 arr = new ArrayList<MetaMethod>(4);
21 map.put(declClass, arr);
22 }
23 arr.add(method);
24 instanceMethods.add(method);
25 }
26 } catch (Throwable e) {
27
28 } else {
29
30 }
31 }
2 if (useMethodWrapper) { // 我們只看useMethodWrapper為true的情況
3 try {
4 List<GeneratedMetaMethod.DgmMethodRecord> records = GeneratedMetaMethod.DgmMethodRecord.loadDgmInfo(); // 從META-INF/dgminfo文件中讀取DGM方法和包裝類的對(duì)應(yīng)關(guān)系
5
6 for (GeneratedMetaMethod.DgmMethodRecord record : records) {
7 Class[] newParams = new Class[record.parameters.length - 1];
8 System.arraycopy(record.parameters, 1, newParams, 0, record.parameters.length-1);
9
10 MetaMethod method = new GeneratedMetaMethod.Proxy(
11 record.className,
12 record.methodName,
13 ReflectionCache.getCachedClass(record.parameters[0]),
14 record.returnType,
15 newParams
16 ); // 為包裝類創(chuàng)建GeneratedMetaMethod.Proxy代理
17 final CachedClass declClass = method.getDeclaringClass();
18 List<MetaMethod> arr = map.get(declClass);
19 if (arr == null) {
20 arr = new ArrayList<MetaMethod>(4);
21 map.put(declClass, arr);
22 }
23 arr.add(method);
24 instanceMethods.add(method);
25 }
26 } catch (Throwable e) {
27

28 } else {
29

30 }
31 }
最后來(lái)看看GeneratedMetaMethod.Proxy如何實(shí)現(xiàn)延遲加載包裝類:
1 public static class Proxy extends GeneratedMetaMethod {
2 private volatile MetaMethod proxy;
3 private final String className;
4
5 public Object invoke(Object object, Object[] arguments) {
6 return proxy().invoke(object, arguments);
7 }
8
9 public final synchronized MetaMethod proxy() {
10 // 第一次調(diào)用時(shí),通過(guò)createProxy創(chuàng)建包裝類實(shí)例
11 if (proxy == null) {
12 createProxy();
13 }
14 return proxy;
15 }
16
17 private void createProxy() {
18 try {
19 // 載入包裝類并進(jìn)行實(shí)例化
20 Class<?> aClass = getClass().getClassLoader().loadClass(className.replace('/','.'));
21 Constructor<?> constructor = aClass.getConstructor(String.class, CachedClass.class, Class.class, Class[].class);
22 proxy = (MetaMethod) constructor.newInstance(getName(), getDeclaringClass(), getReturnType(), getNativeParameterTypes());
23 }
24 catch (Throwable t) {
25 t.printStackTrace();
26 throw new GroovyRuntimeException("Failed to create DGM method proxy : " + t, t);
27 }
28 }
29 }
2 private volatile MetaMethod proxy;
3 private final String className;
4

5 public Object invoke(Object object, Object[] arguments) {
6 return proxy().invoke(object, arguments);
7 }
8
9 public final synchronized MetaMethod proxy() {
10 // 第一次調(diào)用時(shí),通過(guò)createProxy創(chuàng)建包裝類實(shí)例
11 if (proxy == null) {
12 createProxy();
13 }
14 return proxy;
15 }
16
17 private void createProxy() {
18 try {
19 // 載入包裝類并進(jìn)行實(shí)例化
20 Class<?> aClass = getClass().getClassLoader().loadClass(className.replace('/','.'));
21 Constructor<?> constructor = aClass.getConstructor(String.class, CachedClass.class, Class.class, Class[].class);
22 proxy = (MetaMethod) constructor.newInstance(getName(), getDeclaringClass(), getReturnType(), getNativeParameterTypes());
23 }
24 catch (Throwable t) {
25 t.printStackTrace();
26 throw new GroovyRuntimeException("Failed to create DGM method proxy : " + t, t);
27 }
28 }
29 }
以上分析有不當(dāng)之處敬請(qǐng)指出,謝謝大家的閱讀。
posted on 2011-04-26 15:24 Johnny Jian 閱讀(2766) 評(píng)論(0) 編輯 收藏 所屬分類: Groovy