深入分析Spring源码(二)----代理模式(jdk动态代理)

偏执的太偏执、 2021-12-10 08:59 331阅读 0赞

代理模式:

特点:1.有执行者,被代理人两个角色

  1. 2.对于被代理人来说,这件事情是一定要做的,但自己又不想做或者没有时间做,找代理
  2. 3.需要获取被代理人的个人资料

首先来看一下如何使用JDK动态代理。JDK提供了java.lang.reflect.Proxy类来实现动态代理的,可通过它的newProxyInstance来获得代理实现类。同时对于代理的接口的实际处理,是一个java.lang.reflect.InvocationHandler,它提供了一个invoke方法供实现者提供相应的代理逻辑的实现。可以对实际的实现进行一些特殊的处理,像Spring AOP中的各种advice。

  1. //静态代理
  2. public interface Person{
  3. void sing();
  4. String getName();
  5. String getSex();
  6. }
  7. public class Star implements Person{
  8. private String name = "Gongxiaoxiao";
  9. private String sex = "female";
  10. @Override
  11. public void sing(){
  12. System.out.println("===Star====Sing===");
  13. }
  14. }
  15. public class Agent implements Person{
  16. private Person p;
  17. Agent(Person p ){
  18. this.p = p;
  19. }
  20. @Override
  21. public void sing(){
  22. System.out.println("====唱歌前谈价钱===");
  23. p.sing();
  24. System.out.println("======唱歌后护送离场====");
  25. }
  26. }
  27. public static void main(String[] args){
  28. Person p = new Star();
  29. Agent aa = new Agent(p);
  30. aa.sing();
  31. }
  32. //动态代理
  33. public interface Person{
  34. public void sing();
  35. }
  36. public class Star implements Person{
  37. @Override
  38. public void sing(){
  39. System.out.println("===Star====Sing===");
  40. }
  41. }
  42. public class Agent implements InvocationHandler{
  43. private Person target;
  44. //获取被代理人的个人资料
  45. public Object getInstance(Person target) throws Exception{
  46. this.target = target;
  47. //Proxy.newProxyInstance(ClassLoader loader,Class<?>
  48. // []interfaces,InvocationHandler h);
  49. Class clazz = target.getClass();
  50. //参数1:被代理人对应的类加载器,参数2:被代理人对应实现的接口,参数3:代理人;返回代
  51. //理对象
  52. //类加载器(ClassLoader)用来加载动态代理类
  53. //一个要实现接口的数组,从这点就可以看出,要想使用JDK动态代理,必须要有接口类
  54. return
  55. Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
  56. }
  57. @Override
  58. public Object invoke(Object proxy,Method method,Object[]args){
  59. System.out.println("=====付出场费=====");
  60. method.invoke(target,args);
  61. System.out.println("=====护送离场=====");
  62. }
  63. }
  64. public static void main(String[] args){
  65. //设置sun.misc.ProxyGenerator.saveGeneratedFiles这个系统属性为true来把生成的class保存到
  66. //本地文件来查看。
  67. System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
  68. Person p = new Star();
  69. Person aa = (Person)Agent.getInstance(p);
  70. //该代理对象的引用aa的运行时类为 $Proxy0
  71. System.out.println(aa.getClass());
  72. aa.sing();
  73. }
  74. public static Object newProxyInstance(ClassLoader loader,
  75. Class<?>[] interfaces,
  76. InvocationHandler h)
  77. throws IllegalArgumentException {
  78. if (h == null) {
  79. throw new NullPointerException();
  80. }
  81. final Class<?>[] intfs = interfaces.clone();
  82. final SecurityManager sm = System.getSecurityManager();
  83. if (sm != null) {
  84. checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
  85. }
  86. // 这里是生成class的地方
  87. Class<?> cl = getProxyClass0(loader, intfs);
  88. // 使用我们实现的InvocationHandler作为参数调用构造方法来获得代理类的实例
  89. try {
  90. final Constructor<?> cons = cl.getConstructor(constructorParams);
  91. final InvocationHandler ih = h;
  92. if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(cl)) {
  93. return AccessController.doPrivileged(new PrivilegedAction<Object>() {
  94. public Object run() {
  95. return newInstance(cons, ih);
  96. }
  97. });
  98. } else {
  99. return newInstance(cons, ih);
  100. }
  101. } catch (NoSuchMethodException e) {
  102. throw new InternalError(e.toString());
  103. }
  104. }
  105. 其中newInstance只是调用Constructor.newInstance来构造相应的代理类实例,这里重点是看getProxyClass0这个方法的实现:
  106. private static Class<?> getProxyClass0(ClassLoader loader,
  107. Class<?>... interfaces) {
  108. // 代理的接口数量不能超过65535(没有这种变态吧)
  109. if (interfaces.length > 65535) {
  110. throw new IllegalArgumentException("interface limit exceeded");
  111. }
  112. // JDK对代理进行了缓存,如果已经存在相应的代理类,则直接返回,否则才会通过ProxyClassFactory来创建代理
  113. return proxyClassCache.get(loader, interfaces);
  114. }
  115. 其中代理缓存是使用WeakCache实现的,如下
  116. private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
  117. proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
  118. 具体的缓存逻辑这里暂不关心,只需要关心ProxyClassFactory是如何生成代理类的,ProxyClassFactoryProxy的一个静态内部类,实现了WeakCache的内部接口BiFunctionapply方法:
  119. private static final class ProxyClassFactory
  120. implements BiFunction<ClassLoader, Class<?>[], Class<?>> {
  121. // 所有代理类名字的前缀
  122. private static final String proxyClassNamePrefix = "$Proxy";
  123. // 用于生成代理类名字的计数器
  124. private static final AtomicLong nextUniqueNumber = new AtomicLong();
  125. @Override
  126. public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
  127. // 省略验证代理接口的代码……
  128. String proxyPkg = null; // 生成的代理类的包名
  129. // 对于非公共接口,代理类的包名与接口的相同
  130. for (Class<?> intf : interfaces) {
  131. int flags = intf.getModifiers();
  132. if (!Modifier.isPublic(flags)) {
  133. String name = intf.getName();
  134. int n = name.lastIndexOf('.');
  135. String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
  136. if (proxyPkg == null) {
  137. proxyPkg = pkg;
  138. } else if (!pkg.equals(proxyPkg)) {
  139. throw new IllegalArgumentException(
  140. "non-public interfaces from different packages");
  141. }
  142. }
  143. }
  144. // 对于公共接口的包名,默认为com.sun.proxy
  145. if (proxyPkg == null) {
  146. proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
  147. }
  148. // 获取计数
  149. long num = nextUniqueNumber.getAndIncrement();
  150. // 默认情况下,代理类的完全限定名为:com.sun.proxy.$Proxy0,com.sun.proxy.$Proxy1……依次递增
  151. String proxyName = proxyPkg + proxyClassNamePrefix + num;
  152. // 这里才是真正的生成代理类的字节码的地方
  153. byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
  154. proxyName, interfaces);
  155. try {
  156. // 根据二进制字节码返回相应的Class实例
  157. return defineClass0(loader, proxyName,
  158. proxyClassFile, 0, proxyClassFile.length);
  159. } catch (ClassFormatError e) {
  160. throw new IllegalArgumentException(e.toString());
  161. }
  162. }
  163. }
  164. ProxyGeneratorsun.misc包中的类,它没有开源,但是可以反编译来一探究竟:
  165. public static byte[] generateProxyClass(final String var0, Class[] var1) {
  166. ProxyGenerator var2 = new ProxyGenerator(var0, var1);
  167. final byte[] var3 = var2.generateClassFile();
  168. // 这里根据参数配置,决定是否把生成的字节码(.class文件)保存到本地磁盘,我们可以通过把相应的class文件保存到本地,再反编译来看看具体的实现,这样更直观
  169. if(saveGeneratedFiles) {
  170. AccessController.doPrivileged(new PrivilegedAction() {
  171. public Void run() {
  172. try {
  173. FileOutputStream var1 = new FileOutputStream(ProxyGenerator.dotToSlash(var0) + ".class");
  174. var1.write(var3);
  175. var1.close();
  176. return null;
  177. } catch (IOException var2) {
  178. throw new InternalError("I/O exception saving generated file: " + var2);
  179. }
  180. }
  181. });
  182. }
  183. return var3;
  184. }

对生成的代理类进行反编译可得:

  1. //
  2. // Source code recreated from a .class file by IntelliJ IDEA
  3. // (powered by Fernflower decompiler)
  4. //
  5. package com.sun.proxy;
  6. import com.example.demo1.dynamicProxy.Person;
  7. import java.lang.reflect.InvocationHandler;
  8. import java.lang.reflect.Method;
  9. import java.lang.reflect.Proxy;
  10. import java.lang.reflect.UndeclaredThrowableException;
  11. public final class $Proxy0 extends Proxy implements Person {
  12. private static Method m1;
  13. private static Method m4;
  14. private static Method m3;
  15. private static Method m2;
  16. private static Method m5;
  17. private static Method m0;
  18. public $Proxy0(InvocationHandler var1) throws {
  19. super(var1);
  20. }
  21. public final boolean equals(Object var1) throws {
  22. try {
  23. return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
  24. } catch (RuntimeException | Error var3) {
  25. throw var3;
  26. } catch (Throwable var4) {
  27. throw new UndeclaredThrowableException(var4);
  28. }
  29. }
  30. public final String getSex() throws {
  31. try {
  32. return (String)super.h.invoke(this, m4, (Object[])null);
  33. } catch (RuntimeException | Error var2) {
  34. throw var2;
  35. } catch (Throwable var3) {
  36. throw new UndeclaredThrowableException(var3);
  37. }
  38. }
  39. public final String getName() throws {
  40. try {
  41. return (String)super.h.invoke(this, m3, (Object[])null);
  42. } catch (RuntimeException | Error var2) {
  43. throw var2;
  44. } catch (Throwable var3) {
  45. throw new UndeclaredThrowableException(var3);
  46. }
  47. }
  48. public final String toString() throws {
  49. try {
  50. return (String)super.h.invoke(this, m2, (Object[])null);
  51. } catch (RuntimeException | Error var2) {
  52. throw var2;
  53. } catch (Throwable var3) {
  54. throw new UndeclaredThrowableException(var3);
  55. }
  56. }
  57. public final void sing() throws {
  58. try {
  59. super.h.invoke(this, m5, (Object[])null);
  60. } catch (RuntimeException | Error var2) {
  61. throw var2;
  62. } catch (Throwable var3) {
  63. throw new UndeclaredThrowableException(var3);
  64. }
  65. }
  66. public final int hashCode() throws {
  67. try {
  68. return (Integer)super.h.invoke(this, m0, (Object[])null);
  69. } catch (RuntimeException | Error var2) {
  70. throw var2;
  71. } catch (Throwable var3) {
  72. throw new UndeclaredThrowableException(var3);
  73. }
  74. }
  75. static {
  76. try {
  77. m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
  78. m4 = Class.forName("com.example.demo1.dynamicProxy.Person").getMethod("getSex");
  79. m3 = Class.forName("com.example.demo1.dynamicProxy.Person").getMethod("getName");
  80. m2 = Class.forName("java.lang.Object").getMethod("toString");
  81. m5 = Class.forName("com.example.demo1.dynamicProxy.Person").getMethod("sing");
  82. m0 = Class.forName("java.lang.Object").getMethod("hashCode");
  83. } catch (NoSuchMethodException var2) {
  84. throw new NoSuchMethodError(var2.getMessage());
  85. } catch (ClassNotFoundException var3) {
  86. throw new NoClassDefFoundError(var3.getMessage());
  87. }
  88. }
  89. }

生成的动态代理类$Proxy0的特性:

  1. 继承了Proxy类,实现了代理的接口,由于java不能多继承,这里已经继承了Proxy类了,不能再继承其他的类,所以JDK的动态代理不支持对实现类的代理,只支持接口的代理。

提供了一个使用InvocationHandler作为参数的构造方法。
生成静态代码块来初始化接口中方法的Method对象,以及Object类的equals、hashCode、toString方法。
重写了Object类的equals、hashCode、toString,它们都只是简单的调用了InvocationHandler的invoke方法,即可以对其进行特殊的操作,也就是说JDK的动态代理还可以代理上述三个方法。
代理类实现代理接口的sing方法中,只是简单的调用了InvocationHandler的invoke方法,我们可以在invoke方法中进行一些特殊操作,甚至不调用实现的方法,直接返回。

至此JDK动态代理的实现原理就分析的差不多了。同时我们可以想像一下Spring AOP提供的各种拦截该如何实现,就已经很明了了,如下所示:

  1. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  2. // BeforeAdvice
  3. Object retVal = null;
  4. try {
  5. // AroundAdvice
  6. retVal = method.invoke(target, args);
  7. // AroundAdvice
  8. // AfterReturningAdvice
  9. }
  10. catch (Throwable e) {
  11. // AfterThrowingAdvice
  12. }
  13. finally {
  14. // AfterAdvice
  15. }
  16. return retVal;
  17. }

(源码分析部分来自于https://blog.csdn.net/mhmyqn/article/details/48474815)

发表评论

表情:
评论列表 (有 0 条评论,331人围观)

还没有评论,来说两句吧...

相关阅读

    相关 代理模式-JDK动态代理

    对比静态代理 静态代理:是指在程序运行前就已经定义好了目标类的代理类。代理类与目标类的代理关系在程序运行之前就确立了。 动态代理:是指程序在整个运行过程中根本就不存在目标类

    相关 分析JDK动态代理

    引言 动态代理非常的重要,虽然我们在日常的工作中没有非常底层的 编写过动态代理的代码,但是动态代理却起着非常重要的功能,想一下我们经常使用的框架: 日志框架、AOP等等,

    相关 JDK动态代理分析

    一、代理模式是什么? 代理模式就是给一个对象提供一个代理对象,并由代理对象管理着被代理对象的引用。就像生活中的代理律师,你只需要找好代理律师,剩下的都交给代理律师来打理。