JDK动态代理实现原理.docx
- 文档编号:12188149
- 上传时间:2023-04-17
- 格式:DOCX
- 页数:21
- 大小:26.58KB
JDK动态代理实现原理.docx
《JDK动态代理实现原理.docx》由会员分享,可在线阅读,更多相关《JDK动态代理实现原理.docx(21页珍藏版)》请在冰豆网上搜索。
JDK动态代理实现原理
之前虽然会用JDK的动态代理,但是有些问题却一直没有搞明白。
比如说:
InvocationHandler的invoke方法是由谁来调用的,代理对象是怎么生成的,直到前几个星期才把这些问题全部搞明白了。
废话不多说了,先来看一下JDK的动态是怎么用的。
Java代码
1.package dynamic.proxy;
2.
3.import java.lang.reflect.InvocationHandler;
4.import java.lang.reflect.Method;
5.import java.lang.reflect.Proxy;
6.
7./**
8. * 实现自己的InvocationHandler
9. * @author zyb
10. * @since 2012-8-9
11. *
12. */
13.public class MyInvocationHandler implements InvocationHandler {
14.
15. // 目标对象
16. private Object target;
17.
18. /**
19. * 构造方法
20. * @param target 目标对象
21. */
22. public MyInvocationHandler(Object target) {
23. super();
24. this.target = target;
25. }
26.
27.
28. /**
29. * 执行目标对象的方法
30. */
31. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
32.
33. // 在目标对象的方法执行之前简单的打印一下
34. System.out.println("------------------before------------------");
35.
36. // 执行目标对象的方法
37. Object result = method.invoke(target, args);
38.
39. // 在目标对象的方法执行之后简单的打印一下
40. System.out.println("-------------------after------------------");
41.
42. return result;
43. }
44.
45. /**
46. * 获取目标对象的代理对象
47. * @return 代理对象
48. */
49. public Object getProxy() {
50. return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
51. target.getClass().getInterfaces(), this);
52. }
53.}
54.
55.package dynamic.proxy;
56.
57./**
58. * 目标对象实现的接口,用JDK来生成代理对象一定要实现一个接口
59. * @author zyb
60. * @since 2012-8-9
61. *
62. */
63.public interface UserService {
64.
65. /**
66. * 目标方法
67. */
68. public abstract void add();
69.
70.}
71.
72.package dynamic.proxy;
73.
74./**
75. * 目标对象
76. * @author zyb
77. * @since 2012-8-9
78. *
79. */
80.public class UserServiceImpl implements UserService {
81.
82. /* (non-Javadoc)
83. * @see dynamic.proxy.UserService#add()
84. */
85. public void add() {
86. System.out.println("--------------------add---------------");
87. }
88.}
89.
90.package dynamic.proxy;
91.
92.import org.junit.Test;
93.
94./**
95. * 动态代理测试类
96. * @author zyb
97. * @since 2012-8-9
98. *
99. */
100.public class ProxyTest {
101.
102. @Test
103. public void testProxy() throws Throwable {
104. // 实例化目标对象
105. UserService userService = new UserServiceImpl();
106.
107. // 实例化InvocationHandler
108. MyInvocationHandler invocationHandler = new MyInvocationHandler(userService);
109.
110. // 根据目标对象生成代理对象
111. UserService proxy = (UserService) invocationHandler.getProxy();
112.
113. // 调用代理对象的方法
114. proxy.add();
115.
116. }
117.}
执行结果如下:
------------------before------------------
--------------------add---------------
-------------------after------------------
用起来是很简单吧,其实这里基本上就是AOP的一个简单实现了,在目标对象的方法执行之前和执行之后进行了增强。
Spring的AOP实现其实也是用了Proxy和InvocationHandler这两个东西的。
用起来是比较简单,但是如果能知道它背后做了些什么手脚,那就更好不过了。
首先来看一下JDK是怎样生成代理对象的。
既然生成代理对象是用的Proxy类的静态方newProxyInstance,那么我们就去它的源码里看一下它到底都做了些什么?
Java代码
1./**
2. * loader:
类加载器
3. * interfaces:
目标对象实现的接口
4. * h:
InvocationHandler的实现类
5. */
6.public static Object newProxyInstance(ClassLoader loader,
7. Class
>[] interfaces,
8. InvocationHandler h)
9. throws IllegalArgumentException
10. {
11. if (h == null) {
12. throw new NullPointerException();
13. }
14.
15. /*
16. * Look up or generate the designated proxy class.
17. */
18. Class cl = getProxyClass(loader, interfaces);
19.
20. /*
21. * Invoke its constructor with the designated invocation handler.
22. */
23. try {
24. // 调用代理对象的构造方法(也就是$Proxy0(InvocationHandler h))
25. Constructor cons = cl.getConstructor(constructorParams);
26. // 生成代理类的实例并把MyInvocationHandler的实例传给它的构造方法
27. return (Object) cons.newInstance(new Object[] { h });
28. } catch (NoSuchMethodException e) {
29. throw new InternalError(e.toString());
30. } catch (IllegalAccessException e) {
31. throw new InternalError(e.toString());
32. } catch (InstantiationException e) {
33. throw new InternalError(e.toString());
34. } catch (InvocationTargetException e) {
35. throw new InternalError(e.toString());
36. }
37. }
我们再进去getProxyClass方法看一下
Java代码
1.public static Class
> getProxyClass(ClassLoader loader,
2. Class
>... interfaces)
3. throws IllegalArgumentException
4. {
5. // 如果目标类实现的接口数大于65535个则抛出异常(我XX,谁会写这么NB的代码啊?
)
6. if (interfaces.length > 65535) {
7. throw new IllegalArgumentException("interface limit exceeded");
8. }
9.
10. // 声明代理对象所代表的Class对象(有点拗口)
11. Class proxyClass = null;
12.
13. String[] interfaceNames = new String[interfaces.length];
14.
15. Set interfaceSet = new HashSet(); // for detecting duplicates
16.
17. // 遍历目标类所实现的接口
18. for (int i = 0; i < interfaces.length; i++) {
19.
20. // 拿到目标类实现的接口的名称
21. String interfaceName = interfaces[i].getName();
22. Class interfaceClass = null;
23. try {
24. // 加载目标类实现的接口到内存中
25. interfaceClass = Class.forName(interfaceName, false, loader);
26. } catch (ClassNotFoundException e) {
27. }
28. if (interfaceClass !
= interfaces[i]) {
29. throw new IllegalArgumentException(
30. interfaces[i] + " is not visible from class loader");
31. }
32.
33. // 中间省略了一些无关紧要的代码 .......
34.
35. // 把目标类实现的接口代表的Class对象放到Set中
36. interfaceSet.add(interfaceClass);
37.
38. interfaceNames[i] = interfaceName;
39. }
40.
41. // 把目标类实现的接口名称作为缓存(Map)中的key
42. Object key = Arrays.asList(interfaceNames);
43.
44. Map cache;
45.
46. synchronized (loaderToCache) {
47. // 从缓存中获取cache
48. cache = (Map) loaderToCache.get(loader);
49. if (cache == null) {
50. // 如果获取不到,则新建地个HashMap实例
51. cache = new HashMap();
52. // 把HashMap实例和当前加载器放到缓存中
53. loaderToCache.put(loader, cache);
54. }
55.
56. }
57.
58. synchronized (cache) {
59.
60. do {
61. // 根据接口的名称从缓存中获取对象
62. Object value = cache.get(key);
63. if (value instanceof Reference) {
64. proxyClass = (Class) ((Reference) value).get();
65. }
66. if (proxyClass !
= null) {
67. // 如果代理对象的Class实例已经存在,则直接返回
68. return proxyClass;
69. } else if (value == pendingGenerationMarker) {
70. try {
71. cache.wait();
72. } catch (InterruptedException e) {
73. }
74. continue;
75. } else {
76. cache.put(key, pendingGenerationMarker);
77. break;
78. }
79. } while (true);
80. }
81.
82. try {
83. // 中间省略了一些代码 .......
84.
85. // 这里就是动态生成代理对象的最关键的地方
86. byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
87. proxyName, interfaces);
88. try {
89. // 根据代理类的字节码生成代理类的实例
90. proxyClass = defineClass0(loader, proxyName,
91. proxyClassFile, 0, proxyClassFile.length);
92. } catch (ClassFormatError e) {
93. throw new IllegalArgumentException(e.toString());
94. }
95. }
96. // add to set of all generated proxy classes, for isProxyClass
97. proxyClasses.put(proxyClass, null);
98.
99. }
100. // 中间省略了一些代码 .......
101.
102. return proxyClass;
103. }
进去ProxyGenerator类的静态方法generateProxyClass,这里是真正生成代理类class字节码的地方。
Java代码
1.public static byte[] generateProxyClass(final String name,
2. Class[] interfaces)
3. {
4. ProxyGenerator gen = new ProxyGenerator(name, interfaces);
5. // 这里动态生成代理类的字节码,由于比较复杂就不进去看了
6. final byte[] classFile = gen.generateClassFile();
7.
8. // 如果saveGeneratedFiles的值为true,则会把所生成的代理类的字节码保存到硬盘上
9. if (saveGeneratedFiles) {
10. java.security.AccessController.doPrivileged(
11. new java.security.PrivilegedAction
12. public Void run() {
13. try {
14. FileOutputStream file =
15. new FileOutputStream(dotToSlash(name) + ".class");
16. file.write(classFile);
17. file.close();
18. return null;
19. } catch (IOException e) {
20. throw new InternalError(
21. "I/O exception saving generated file:
" + e);
22. }
23. }
24. });
25. }
26.
27. // 返回代理类的字节码
28. return classFile;
29. }
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- JDK 动态 代理 实现 原理