• JDK的动态代理解读


    动态代理即在不改变某个类的源码(被代理类)的情况下对源码做些操作,比如统计某个方法的执行时间,在某个方法前边或后边输出条日志等等。比如AOP

    废话:无

    正事:start

    请先阅读代码后在看这段文字辅助理解。

    我理解的动态代理原理:

    Subject subject = Proxy.newProxyInstance(
            handler.getClass().getClassLoader(),
            realiSubject.getClass().getInterfaces(),
            handler);

    这行代码直接生成了动态代理类实例(如何生成的...理解不够不晓得咋描述),

    它有三个参数,分别为:

    1:代理类或被代理类的类加载器(类加载器这块有点薄弱,理解下)

    2:被代理类所实现的接口

    3:实现了InvocationHandler接口的代理类

    返回值subject这个局部变量就是被生成的动态代理类实例$Proxy0(这点很重要)

    至于subject.hello("lilei") (subject.hai()同理)这行代码是如何执行的动态代理操作的,则可以通过第二部分的代码块代码阅读发现。

    我们可以看见$Proxy0中的hello()方法就做了一个事就是

    调用父类(Proxy类)h变量(InvocationHandler,这是个接口)的invoke方法,接口的方法在实际执行的时候都是执行的实现该接口的具体类的实例的方法,所以这个方法执行的是我们实现了InvocationHandler接口的代理类中的invoke。

    invoke的参数可以自己查看$Proxy0中的hello方法,注:proxy参数是个形参,我认为无用,有知道的可以评论补充下。

    注:$Proxy0中的静态代码块应一定阅读

    代码:

    这段代码是我们手动敲的代理代码(可直接复制到你的idea中),其中:

    RealSubject:被代理类
    Subject:被代理类实现的接口
    DynamicProxy:代理类
    InvocationHandler:jdk自带的动态代理类接口
    DemoProxy:main方法所在的类
    1. import java.lang.reflect.InvocationHandler;
    2. import java.lang.reflect.Method;
    3. import java.lang.reflect.Proxy;
    4. public class DemoProxy {
    5. public static void main(String[] args) {
    6. System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
    7. Subject realiSubject = new RealSubject();
    8. InvocationHandler handler = new DynamicProxy(realiSubject);
    9. Subject subject = (Subject) Proxy.newProxyInstance(
    10. handler.getClass().getClassLoader(),
    11. realiSubject.getClass().getInterfaces(),
    12. handler);
    13. System.out.println(subject.getClass().getName());
    14. subject.hello("lilei");
    15. subject.hai();
    16. }
    17. }
    18. interface Subject {
    19. void hello (String str);
    20. void hai ();
    21. }
    22. class RealSubject implements Subject {
    23. @Override
    24. public void hello(String str) {
    25. System.out.println("hello " + str);
    26. }
    27. @Override
    28. public void hai() {
    29. System.out.println("hai");
    30. }
    31. }
    32. class DynamicProxy implements InvocationHandler {
    33. private Object subject;
    34. public DynamicProxy (Object obj) {
    35. subject = obj;
    36. }
    37. @Override
    38. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    39. System.out.println("before hello ...");
    40. System.out.println("Method: " + method + "" + method.getDeclaringClass().getName());
    41. method.invoke(subject, args);
    42. // Subject subj = (Subject)subject;
    43. // subj.hello(args == null ? "" : (String)args[0]);
    44. System.out.println("after hello ...");
    45. return null;
    46. }
    47. }

     下边的这个代码是上边的代码生成的动态代理类,在Proxy.newProxyInstance这行代码执行完后生成的。将生成的动态代理类展示(就这个意思)出来的代码是这行:(我用的jdk8)

    System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");

    这段代码没必要赋值,你执行成功上边的代码,这段代码就会自动生成了

    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. final class $Proxy0 extends Proxy implements Subject {
    6. private static Method m1;
    7. private static Method m2;
    8. private static Method m4;
    9. private static Method m3;
    10. private static Method m0;
    11. public $Proxy0(InvocationHandler var1) throws {
    12. super(var1);
    13. }
    14. public final boolean equals(Object var1) throws {
    15. try {
    16. return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
    17. } catch (RuntimeException | Error var3) {
    18. throw var3;
    19. } catch (Throwable var4) {
    20. throw new UndeclaredThrowableException(var4);
    21. }
    22. }
    23. public final String toString() throws {
    24. try {
    25. return (String)super.h.invoke(this, m2, (Object[])null);
    26. } catch (RuntimeException | Error var2) {
    27. throw var2;
    28. } catch (Throwable var3) {
    29. throw new UndeclaredThrowableException(var3);
    30. }
    31. }
    32. public final void hai() throws {
    33. try {
    34. super.h.invoke(this, m4, (Object[])null);
    35. } catch (RuntimeException | Error var2) {
    36. throw var2;
    37. } catch (Throwable var3) {
    38. throw new UndeclaredThrowableException(var3);
    39. }
    40. }
    41. public final void hello(String var1) throws {
    42. try {
    43. super.h.invoke(this, m3, new Object[]{var1});
    44. } catch (RuntimeException | Error var3) {
    45. throw var3;
    46. } catch (Throwable var4) {
    47. throw new UndeclaredThrowableException(var4);
    48. }
    49. }
    50. public final int hashCode() throws {
    51. try {
    52. return (Integer)super.h.invoke(this, m0, (Object[])null);
    53. } catch (RuntimeException | Error var2) {
    54. throw var2;
    55. } catch (Throwable var3) {
    56. throw new UndeclaredThrowableException(var3);
    57. }
    58. }
    59. static {
    60. try {
    61. m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
    62. m2 = Class.forName("java.lang.Object").getMethod("toString");
    63. m4 = Class.forName("com.mashibing.nw.dongtaidaili.Subject").getMethod("hai");
    64. m3 = Class.forName("com.mashibing.nw.dongtaidaili.Subject").getMethod("hello", Class.forName("java.lang.String"));
    65. m0 = Class.forName("java.lang.Object").getMethod("hashCode");
    66. } catch (NoSuchMethodException var2) {
    67. throw new NoSuchMethodError(var2.getMessage());
    68. } catch (ClassNotFoundException var3) {
    69. throw new NoClassDefFoundError(var3.getMessage());
    70. }
    71. }
    72. }

    简单提醒:

    idea在debug模式下会每走一步就调用一下toString方法(为啥调用不清楚,清楚的大佬评论补充下),所以故而导致我们的invoke方法会被多次执行

    在run模式下就没有这些问题

  • 相关阅读:
    从底层看 Redis 的五种数据类型
    java选择结构
    算法详解——贪心算法
    QT-day4作业
    Github流出高质量高并发手册,看完面试手稳心不慌,吊打敢于提问高并发的面试官
    Linux权限
    面板平滑转换回归(PSTR)分析案例实现
    泰山OFFICE技术讲座:关于文字方向的几种实现思路
    应用程序通过 Envoy 代理和 Jaeger 进行分布式追踪 —— Ingress Controller + Http服务 + Grpc服务(三)
    【从零开始的Java开发】1-4-1 Java继承:Object类、final关键字、注解
  • 原文地址:https://blog.csdn.net/m15231417197/article/details/126039233