詳解java JDK 動態代理類分析(java.lang.reflect.Proxy)
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
|
/** * JDK 動態代理類分析(java.lang.reflect.Proxy使用) * * @author 張明學 * */ public class ProxyStudy { @SuppressWarnings ( "unchecked" ) public static void main(String[] args) throws Exception { // 動態代理類:通用指定類加載器,和接口產生一類 // getProxyClass()返回代理類的 java.lang.Class 對象,并向其提供類加載器和接口數組。 Class clazzProxy = Proxy.getProxyClass(Collection. class .getClassLoader(), Collection. class ); System.out.println( "動態產生的類名為:" + clazzProxy.getName()); System.out.println( "----------獲取動態產生的類的構造方法---------" ); Constructor[] constructors = clazzProxy.getConstructors(); int i = 1 ; for (Constructor constructor : constructors) { System.out.println( "第" + (i++) + "個構造方法名:" + constructor.getName()); Class[] parameterClazz = constructor.getParameterTypes(); System.out.println( "第" + (i++) + "個構造方法參數:" + Arrays.asList(parameterClazz)); } System.out.println( "----------獲取動態產生的類的普通方法---------" ); Method[] methods = clazzProxy.getDeclaredMethods(); for ( int j = 0 ; j < methods.length; j++) { Method method = methods[j]; System.out.println( "第" + (j + 1 ) + "個普通方法名:" + method.getName()); Class[] parameterClazz = method.getParameterTypes(); System.out.println( "第" + (j + 1 ) + "個普通方法參數:" + Arrays.asList(parameterClazz)); } System.out.println( "---------獲取動態代理對象的構造方法---------" ); // 動態代理產生的對象的構造方法需要一個實現java.lang.reflect.InvocationHandler接口的對象,故不能通過 // clazzProxy.newInstance();產生一個對象,可以根據構造方法產生一個對象 // InvocationHandler 是代理實例的調用處理程序 實現的接口。 Constructor constructor = clazzProxy.getConstructor(InvocationHandler. class ); // 代理產生的對象 Collection proxyBuildCollection = (Collection) constructor .newInstance( new InvocationHandler() { // 為什么這里選擇ArrayList作為目標對象? // 因為這里的constructor是clazzProxy這個動態類的構造方法,clazzProxy是通過Proxy.getProxyClass()方法產生的, // 該方法有兩個參數,一個是指定類加載器,一個是指定代理要實現的接口,這個接口我上面指定了Collection // 而ArrayList實現了Collection接口,固可以為該動態類的目標對象 ArrayList target = new ArrayList(); // 動態類的目標對象 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println( "執行目標" + method.getName() + "方法之前:" + System.currentTimeMillis()); Object result = method.invoke(target, args); // 其實代理對象的方法調用還是目標對象的方法 System.out.println( "執行目標" + method.getName() + "方法之后:" + System.currentTimeMillis()); return result; } }); proxyBuildCollection.clear(); proxyBuildCollection.add( "abc" ); proxyBuildCollection.add( "dbc" ); System.out.println(proxyBuildCollection.size()); System.out.println(proxyBuildCollection.getClass().getName()); /** * 動態代理:總結如下: * 1,通過Proxy.getProxyClass(classLoader,interface)方法產生一個動態類的class字節碼(clazz) * 該getProxyClass()方法有兩個參數:一個是指定該動態類的類加載器,一個是該動態類的要實現的接口(從這里可以看現JDK的動態代理必須要實現一個接口) * * 2,通過第一步的獲取的clazz對象可以獲取它的構造方法constructor,那么就可以通用constructor的newInstance()方法構造出一個動態實體對象 * 但constructor的newInstance()方法需要指定一個實現了InvocationHandler接口的類handler,在該類中需要一個目標對象A和實現invoke方法 * 目標對象A要求能對第一步中的接口的實現,因為在invoke方法中將會去調用A中的方法并返回結果。 * 過程如下:調用動態代理對象ProxyObject的x方法 ————> 進入構造方法傳進的handler的invoke方法 ————> invoke方法調用handler中的target對象 * 的x方法(所以要求target必須要實現構造動態代理類時指定的接口)并返回它的返回值。(其實如果我們代理P類,那么target就可以選中P類,只是要求P必需實現一個接口) * * 那么上述中x方法有哪些呢?除了從Object繼承過來的方法中除toString,hashCode,equals外的方法不交給handler外,其它的方法全部交給handler處理 * 如上面proxyBuildCollection.getClass().getName()就沒有調用handler的getClass方法,而是調用自己的 * * 3,在handler的invoke方法中return method.invoke(target,args)就是將方法交給target去完成。那么在這個方法執行之前,之后,異常時我們都可以做一些操作, * 并且可以在執行之前檢查方法的參數args,執行之后檢查方法的結果 */ System.out.println( "-------------------下面的寫法更簡便--------------------" ); // proxyBuildColl是對ArrayList進行代理 Collection proxyBuildCollection2 = (Collection) Proxy.newProxyInstance( Collection. class .getClassLoader(), // 指定類加載器 new Class[] { Collection. class }, // 指定目標對象實現的接口 // 指定handler new InvocationHandler() { ArrayList target = new ArrayList(); public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println(method.getName() + "執行之前..." ); if ( null != args) { System.out.println( "方法的參數:" + Arrays.asList(args)); } else { System.out.println( "方法的參數:" + null ); } Object result = method.invoke(target, args); System.out.println(method.getName() + "執行之后..." ); return result; } }); proxyBuildCollection2.add( "abc" ); proxyBuildCollection2.size(); proxyBuildCollection2.clear(); proxyBuildCollection2.getClass().getName(); System.out.println( "-------------------對JDK動態代理的重構--------------------" ); Set proxySet = (Set) buildProxy( new HashSet(), new MyAdvice()); proxySet.add( "abc" ); proxySet.size(); } /** * 構造一個目標對象的代理對象 * * @param target * 目標對象(需要實現某個接口) * @return */ public static Object buildProxy( final Object target, final AdviceInter advice) { Object proxyObject = Proxy.newProxyInstance( target.getClass().getClassLoader(), // 指定類加載器 target.getClass().getInterfaces(), // 指定目標對象實現的接口 // handler new InvocationHandler() { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { advice.beforeMethod(target, method, args); Object result = method.invoke(target, args); advice.afterMethod(target, method, args); return result; } }); return proxyObject; } } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
/** * 代理中執行目標方法之前之后的操作的一個實例 * * @author 張明學 * */ public class MyAdvice implements AdviceInter { public void afterMethod(Object target, Method method, Object[] args) { System.out.println( "目標對象為:" + target.getClass().getName()); System.out.println(method.getName() + "執行完畢!" ); } public void beforeMethod(Object target, Method method, Object[] args) { System.out.println(method.getName() + "開始執行" ); if ( null != args) { System.out.println( "參數為:" + Arrays.asList(args)); } else { System.out.println( "參數為:" + null ); } } } |
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
|
/** * 代理中執行目標方法之前之后的操作 * * @author 張明學 * */ public interface AdviceInter { /** * 目標方法執行之前 * */ public void beforeMethod(Object target, Method method, Object[] args); /** * 目標方法執行之后 * * @param target * 目標對象 * @param method * 方法 * @param args * 參數 */ public void afterMethod(Object target, Method method, Object[] args); } |