zoukankan      html  css  js  c++  java
  • Spring核心框架

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

    一.相关类及其方法:

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

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

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

    1、寻找GF接口

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

    2、寻找GF实现类

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

    3、代理类处理

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

    4、动态代理实现

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

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

    二、动态代理步骤总结

    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类的源码

    [html] view plaincopy
     
      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.   
      6. public final class $Proxy0 extends Proxy implements Manager {  
      7.   
      8.     private static Method m1;  
      9.     private static Method m0;  
      10.     private static Method m3;  
      11.     private static Method m2;  
      12.   
      13.     static {  
      14.         try {  
      15.             m1 = Class.forName("java.lang.Object").getMethod("equals",  
      16.                     new Class[] { Class.forName("java.lang.Object") });  
      17.             m0 = Class.forName("java.lang.Object").getMethod("hashCode",  
      18.                     new Class[0]);  
      19.             m3 = Class.forName("com.ml.test.Manager").getMethod("modify",  
      20.                     new Class[0]);  
      21.             m2 = Class.forName("java.lang.Object").getMethod("toString",  
      22.                     new Class[0]);  
      23.         } catch (NoSuchMethodException nosuchmethodexception) {  
      24.             throw new NoSuchMethodError(nosuchmethodexception.getMessage());  
      25.         } catch (ClassNotFoundException classnotfoundexception) {  
      26.             throw new NoClassDefFoundError(classnotfoundexception.getMessage());  
      27.         }  
      28.     }  
      29.   
      30.     public $Proxy0(InvocationHandler invocationhandler) {  
      31.         super(invocationhandler);  
      32.     }  
      33.   
      34.     @Override  
      35.     public final boolean equals(Object obj) {  
      36.         try {  
      37.             return ((Boolean) super.h.invoke(this, m1, new Object[] { obj }))  
      38.                     .booleanValue();  
      39.         } catch (Throwable throwable) {  
      40.             throw new UndeclaredThrowableException(throwable);  
      41.         }  
      42.     }  
      43.   
      44.     @Override  
      45.     public final int hashCode() {  
      46.         try {  
      47.             return ((Integer) super.h.invoke(this, m0, null)).intValue();  
      48.         } catch (Throwable throwable) {  
      49.             throw new UndeclaredThrowableException(throwable);  
      50.         }  
      51.     }  
      52.   
      53.     public final void modify() {  
      54.         try {  
      55.             super.h.invoke(this, m3, null);  
      56.             return;  
      57.         } catch (Error e) {  
      58.         } catch (Throwable throwable) {  
      59.             throw new UndeclaredThrowableException(throwable);  
      60.         }  
      61.     }  
      62.   
      63.     @Override  
      64.     public final String toString() {  
      65.         try {  
      66.             return (String) super.h.invoke(this, m2, null);  
      67.         } catch (Throwable throwable) {  
      68.             throw new UndeclaredThrowableException(throwable);  
      69.         }  
      70.     }  
      71. }  
  • 相关阅读:
    基于网页的暖通空调监控方案
    基于SVG+AJAX的网页数据监控
    基于WebGL的三维的物联网平台技术
    Tomcat部署多个Springboot项目报错 InstanceNotFoundException: com.alibaba.druid:type=DruidDataSourceStat
    MYSQL 快速备份大数据量
    防止过度工程-[拒绝完美主义]
    ES6学习
    Linux系统上java调用C++ so库文件
    第二十四篇 -- Cache学习
    第二十八篇 -- 学习第五十一天打卡20190819
  • 原文地址:https://www.cnblogs.com/downey/p/4888448.html
Copyright © 2011-2022 走看看