Spring核心框架 - AOP之动态代理机制

时间:2023-09-01 14:12:26

动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java 反射机制可以生成任意类型的动态代理类。

一.相关类及其方法:

java.lang.reflect.Proxy,
Proxy 提供用于创建动态代理类和实例的静态方法.
newProxyInstance()返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序

java.lang.reflect.InvocationHandler,
InvocationHandler 是代理实例的调用处理程序实现的接口。 
invoke()在代理实例上处理方法调用并返回结果。在与方法关联的代理实例上调用方法时,将在调用处理程序上调用此方法。

具体实例:联谊会或者相亲

1、寻找GF接口

  1. package com.aop;
  2. /**
  3. * 寻找GF接口
  4. *
  5. * @author Anndy
  6. */
  7. public interface FindGFInterface {
  8. /**
  9. * 寻找GF方法
  10. */
  11. public void findGF();
  12. }

2、寻找GF实现类

  1. package com.aop;
  2. /**
  3. * Anndy寻找GF实现类
  4. *
  5. * @author Anndy
  6. */
  7. public class AnndyFindGFInterfaceImpl implements FindGFInterface {
  8. public void findGF() {
  9. System.out.println("Anndy go to find GF!");
  10. }
  11. }

3、代理类处理

  1. package com.aop;
  2. import java.lang.reflect.InvocationHandler;
  3. import java.lang.reflect.Method;
  4. /**
  5. * 打扮帅点,去约会
  6. *
  7. * @author Anndy
  8. */
  9. public class ReadyInvocationHandler implements InvocationHandler {
  10. private Object anndy = null;
  11. public ReadyInvocationHandler(Object realSubject) {
  12. this.anndy = realSubject;
  13. }
  14. /**
  15. * 动态代理类$Proxy0调用FindGF方法时会调用它自己的FindGF方法,
  16. * 而它自己的FindGF方法里面调用的是super.h.invoke(this, , ),也就是父类Proxy的h的invoke方法,
  17. * 实际上就是ReadyInvocationHandler类的invoke方法。 所以invoke(Object proxy, Method
  18. * m,Object[] args)中的proxy实际上就是动态代理类$Proxy0,
  19. * 在这里不能将其强转成AnndyFindGFInterfaceImpl然后调用它的FindGF方法,会出现死循环
  20. */
  21. public Object invoke(Object proxy, Method m, Object[] args) {
  22. Object result = null;
  23. try {
  24. System.out.println(proxy.getClass().getSimpleName());
  25. System.out.println("Anndy找女朋友,代理人给他打扮了打扮。");
  26. result = m.invoke(anndy, args);
  27. } catch (Exception ex) {
  28. System.exit(1);
  29. }
  30. return result;
  31. }
  32. }

4、动态代理实现

  1. package com.aop;
  2. import java.lang.reflect.Proxy;
  3. /**
  4. * 联谊会现场
  5. *
  6. * @author Anndy
  7. */
  8. public class SceneOfSodality {
  9. public static void main(String args[]) {
  10. /**
  11. * 得到AnndyFindGFInterfaceImpl这个类的一个代理类,
  12. * 同时为代理类绑定了一个处理类ReadyInvocationHandler。
  13. * 每次调用AnndyFindGFInterfaceImpl这个子类的findGF方法时,
  14. * 并不是anndy这个AnndyFindGFInterfaceImpl类的实例去调用,
  15. * 而是这个AnndyFindGFInterfaceImpl的代理类ReadyInvocationHandler去调用它自己的invoke方法
  16. */
  17. // 实例化对象
  18. FindGFInterface anndy = new AnndyFindGFInterfaceImpl();
  19. /**
  20. * java中的动态代理实现 第一步,我们要有一个接口,还要有一个接口的实现类,而这个实现类就是我们要代理的对象,
  21. * 所谓代理就是在调用实现类的方法时,可以在方法执行前后做额外的工作,这个就是代理。
  22. * 第二步,我们要自己写一个在代理类的方法执行时,能够做额外工作的类,而这个类必须继承InvocationHandler接口,
  23. * 因为代理类的实例在调用实现类的方法的时候,不会调真正的实现类的这个方法,
  24. * 而是转而调用这个类的invoke方法(继承时必须实现的方法),在这个方法中你可以调用真正的实现类的这个方法。
  25. * 第三步,在要用代理类的实例去调用实现类的方法的时候,写出下面两段代码。
  26. */
  27. FindGFInterface proxy = (FindGFInterface) Proxy.newProxyInstance(anndy
  28. .getClass().getClassLoader(), anndy.getClass().getInterfaces(),
  29. new ReadyInvocationHandler(anndy));
  30. proxy.findGF();
  31. }
  32. }

到此,上面是整个动态代理的过程。

二、动态代理步骤总结

1、通过实现InvocationHandler接口创建自己的调用处理器 IvocationHandler handler = new InvocationHandlerImpl(...);

2、通过为Proxy类指定ClassLoader对象和一组interface创建动态代理类Class clazz = Proxy.getProxyClass(classLoader,new Class[]{...});

3、通过反射机制获取动态代理类的构造函数,其参数类型是调用处理器接口类型Constructor constructor = clazz.getConstructor(new Class[]{InvocationHandler.class});

4、通过构造函数创建代理类实例,此时需将调用处理器对象作为参数被传入Interface Proxy = (Interface)constructor.newInstance(new Object[] (handler));为了简化对象创建过程,Proxy类中的newInstance方法封装了2~4,只需两步即可完成代理对象的创建。生成的ProxySubject继承Proxy类实现Subject接口,实现的Subject的方法实际调用处理器的invoke方法,而invoke方法利用反射调用的是被代理对象的的方法(Object result=method.invoke(proxied,args))。

三、附录$Proxy0类的源码

    1. import java.lang.reflect.InvocationHandler;
    2. import java.lang.reflect.Method;
    3. import java.lang.reflect.Proxy;
    4. import java.lang.reflect.UndeclaredThrowableException;
    5. public final class $Proxy0 extends Proxy implements Manager {
    6. private static Method m1;
    7. private static Method m0;
    8. private static Method m3;
    9. private static Method m2;
    10. static {
    11. try {
    12. m1 = Class.forName("java.lang.Object").getMethod("equals",
    13. new Class[] { Class.forName("java.lang.Object") });
    14. m0 = Class.forName("java.lang.Object").getMethod("hashCode",
    15. new Class[0]);
    16. m3 = Class.forName("com.ml.test.Manager").getMethod("modify",
    17. new Class[0]);
    18. m2 = Class.forName("java.lang.Object").getMethod("toString",
    19. new Class[0]);
    20. } catch (NoSuchMethodException nosuchmethodexception) {
    21. throw new NoSuchMethodError(nosuchmethodexception.getMessage());
    22. } catch (ClassNotFoundException classnotfoundexception) {
    23. throw new NoClassDefFoundError(classnotfoundexception.getMessage());
    24. }
    25. }
    26. public $Proxy0(InvocationHandler invocationhandler) {
    27. super(invocationhandler);
    28. }
    29. @Override
    30. public final boolean equals(Object obj) {
    31. try {
    32. return ((Boolean) super.h.invoke(this, m1, new Object[] { obj }))
    33. .booleanValue();
    34. } catch (Throwable throwable) {
    35. throw new UndeclaredThrowableException(throwable);
    36. }
    37. }
    38. @Override
    39. public final int hashCode() {
    40. try {
    41. return ((Integer) super.h.invoke(this, m0, null)).intValue();
    42. } catch (Throwable throwable) {
    43. throw new UndeclaredThrowableException(throwable);
    44. }
    45. }
    46. public final void modify() {
    47. try {
    48. super.h.invoke(this, m3, null);
    49. return;
    50. } catch (Error e) {
    51. } catch (Throwable throwable) {
    52. throw new UndeclaredThrowableException(throwable);
    53. }
    54. }
    55. @Override
    56. public final String toString() {
    57. try {
    58. return (String) super.h.invoke(this, m2, null);
    59. } catch (Throwable throwable) {
    60. throw new UndeclaredThrowableException(throwable);
    61. }
    62. }
    63. }