详解java JDK 动态代理类分析(java.lang.reflect.Proxy)

详解java JDK 动态代理类分析(java.lang.reflect.Proxy)

/**
 * JDK 动态代理类分析(java.lang.reflect.Proxy使用)
 *
 * @author 张明学
 *
 */
public class ProxyStudy { 

  @SuppressWarnings("unchecked")
  public static void main(String[] args) throws Exception {
    // 动态代理类:通用指定类加载器,和接口产生一类
    // getProxyClass()返回代理类的 java.lang.Class 对象,并向其提供类加载器和接口数组。
    Class clazzProxy = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);
    System.out.println("动态产生的类名为:" + clazzProxy.getName());
    System.out.println("----------获取动态产生的类的构造方法---------");
    Constructor[] constructors = clazzProxy.getConstructors();
    int i = 1;
    for (Constructor constructor : constructors) {
      System.out.println("第" + (i++) + "个构造方法名:" + constructor.getName());
      Class[] parameterClazz = constructor.getParameterTypes();
      System.out.println("第" + (i++) + "个构造方法参数:" + Arrays.asList(parameterClazz));
    }
    System.out.println("----------获取动态产生的类的普通方法---------");
    Method[] methods = clazzProxy.getDeclaredMethods();
    for (int j = 0; j < methods.length; j++) {
      Method method = methods[j];
      System.out.println("第" + (j + 1) + "个普通方法名:" + method.getName());
      Class[] parameterClazz = method.getParameterTypes();
      System.out.println("第" + (j + 1) + "个普通方法参数:" + Arrays.asList(parameterClazz));
    }
    System.out.println("---------获取动态代理对象的构造方法---------");
    // 动态代理产生的对象的构造方法需要一个实现java.lang.reflect.InvocationHandler接口的对象,故不能通过
    // clazzProxy.newInstance();产生一个对象,可以根据构造方法产生一个对象
    // InvocationHandler 是代理实例的调用处理程序 实现的接口。
    Constructor constructor = clazzProxy.getConstructor(InvocationHandler.class); 

    // 代理产生的对象
    Collection proxyBuildCollection = (Collection) constructor
        .newInstance(new InvocationHandler() {
          // 为什么这里选择ArrayList作为目标对象?
          // 因为这里的constructor是clazzProxy这个动态类的构造方法,clazzProxy是通过Proxy.getProxyClass()方法产生的,
          // 该方法有两个参数,一个是指定类加载器,一个是指定代理要实现的接口,这个接口我上面指定了Collection
          // 而ArrayList实现了Collection接口,固可以为该动态类的目标对象
          ArrayList target = new ArrayList();// 动态类的目标对象 

          public Object invoke(Object proxy, Method method,
              Object[] args) throws Throwable {
            System.out.println("执行目标" + method.getName() + "方法之前:"
                + System.currentTimeMillis());
            Object result = method.invoke(target, args);// 其实代理对象的方法调用还是目标对象的方法
            System.out.println("执行目标" + method.getName() + "方法之后:"
                + System.currentTimeMillis());
            return result;
          } 

        });
    proxyBuildCollection.clear();
    proxyBuildCollection.add("abc");
    proxyBuildCollection.add("dbc");
    System.out.println(proxyBuildCollection.size());
    System.out.println(proxyBuildCollection.getClass().getName()); 

    /**
     * 动态代理:总结如下:
     * 1,通过Proxy.getProxyClass(classLoader,interface)方法产生一个动态类的class字节码(clazz)
     *  该getProxyClass()方法有两个参数:一个是指定该动态类的类加载器,一个是该动态类的要实现的接口(从这里可以看现JDK的动态代理必须要实现一个接口)
     *
     * 2,通过第一步的获取的clazz对象可以获取它的构造方法constructor,那么就可以通用constructor的newInstance()方法构造出一个动态实体对象
     *  但constructor的newInstance()方法需要指定一个实现了InvocationHandler接口的类handler,在该类中需要一个目标对象A和实现invoke方法
     *  目标对象A要求能对第一步中的接口的实现,因为在invoke方法中将会去调用A中的方法并返回结果。
     *  过程如下:调用动态代理对象ProxyObject的x方法 ————> 进入构造方法传进的handler的invoke方法 ————> invoke方法调用handler中的target对象
     *      的x方法(所以要求target必须要实现构造动态代理类时指定的接口)并返回它的返回值。(其实如果我们代理P类,那么target就可以选中P类,只是要求P必需实现一个接口)
     *
     *  那么上述中x方法有哪些呢?除了从Object继承过来的方法中除toString,hashCode,equals外的方法不交给handler外,其它的方法全部交给handler处理
     *  如上面proxyBuildCollection.getClass().getName()就没有调用handler的getClass方法,而是调用自己的
     *
     * 3,在handler的invoke方法中return method.invoke(target,args)就是将方法交给target去完成。那么在这个方法执行之前,之后,异常时我们都可以做一些操作,
     *  并且可以在执行之前检查方法的参数args,执行之后检查方法的结果
     */
    System.out.println("-------------------下面的写法更简便--------------------"); 

    // proxyBuildColl是对ArrayList进行代理
    Collection proxyBuildCollection2 = (Collection) Proxy.newProxyInstance(
        Collection.class.getClassLoader(),// 指定类加载器
        new Class[] { Collection.class },// 指定目标对象实现的接口
        // 指定handler
        new InvocationHandler() {
          ArrayList target = new ArrayList(); 

          public Object invoke(Object proxy, Method method,
              Object[] args) throws Throwable {
            System.out.println(method.getName() + "执行之前...");
            if (null != args) {
              System.out.println("方法的参数:" + Arrays.asList(args));
            } else {
              System.out.println("方法的参数:" + null);
            }
            Object result = method.invoke(target, args);
            System.out.println(method.getName() + "执行之后...");
            return result;
          }
        });
    proxyBuildCollection2.add("abc");
    proxyBuildCollection2.size();
    proxyBuildCollection2.clear();
    proxyBuildCollection2.getClass().getName(); 

    System.out.println("-------------------对JDK动态代理的重构--------------------");
    Set proxySet = (Set) buildProxy(new HashSet(), new MyAdvice());
    proxySet.add("abc");
    proxySet.size();
  }
  /**
   * 构造一个目标对象的代理对象
   *
   * @param target
   *      目标对象(需要实现某个接口)
   * @return
   */
  public static Object buildProxy(final Object target,final AdviceInter advice) {
    Object proxyObject = Proxy.newProxyInstance(
        target.getClass().getClassLoader(),// 指定类加载器
        target.getClass().getInterfaces(), // 指定目标对象实现的接口
        // handler
        new InvocationHandler() { 

          public Object invoke(Object proxy, Method method,
              Object[] args) throws Throwable {
            advice.beforeMethod(target, method, args);
            Object result = method.invoke(target, args);
            advice.afterMethod(target, method, args);
            return result;
          }
        });
    return proxyObject;
  } 

}
/**
 * 代理中执行目标方法之前之后的操作的一个实例
 *
 * @author 张明学
 *
 */
public class MyAdvice implements AdviceInter { 

  public void afterMethod(Object target, Method method, Object[] args) {
    System.out.println("目标对象为:" + target.getClass().getName());
    System.out.println(method.getName() + "执行完毕!");
  } 

  public void beforeMethod(Object target, Method method, Object[] args) {
    System.out.println(method.getName() + "开始执行");
    if (null != args) {
      System.out.println("参数为:" + Arrays.asList(args));
    } else {
      System.out.println("参数为:" + null);
    }
  }
} 
/**
 * 代理中执行目标方法之前之后的操作
 *
 * @author 张明学
 *
 */
public interface AdviceInter {
  /**
   * 目标方法执行之前
   *
   */
  public void beforeMethod(Object target, Method method, Object[] args); 

  /**
   * 目标方法执行之后
   *
   * @param target
   *      目标对象
   * @param method
   *      方法
   * @param args
   *      参数
   */
  public void afterMethod(Object target, Method method, Object[] args);
}
(0)

相关推荐

  • java动态代理(jdk与cglib)详细解析

    JAVA的动态代理 代理模式 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务. 按照代理的创建时期,代理类可以分为两种. 静态代理:由程序员创建或特定工具自动生成源代码,再对其编译.在程序运行前,代理类的.class文件就已经

  • Java JDK动态代理(AOP)的实现原理与使用详析

    本文主要给大家介绍了关于Java JDK动态代理(AOP)实现原理与使用的相关内容,分享出来供大家参考学习,下面来一起看看详细的介绍: 一.什么是代理? 代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问.代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理. 代理模式UML图: 简单结构示意图: 为了保持行为的一致性,代理类和委托类通常会实现相同的接口,所以在访问者看来两者没有丝毫的区别.通过代理类这中间一层,能有效控制对委托类对

  • 深度剖析java中JDK动态代理机制

    摘要 相比于静态代理,动态代理避免了开发人员编写各个繁锁的静态代理类,只需简单地指定一组接口及目标类对象就能动态的获得代理对象. 代理模式 使用代理模式必须要让代理类和目标类实现相同的接口,客户端通过代理类来调用目标方法,代理类会将所有的方法调用分派到目标对象上反射执行,还可以在分派过程中添加"前置通知"和后置处理(如在调用目标方法前校验权限,在调用完目标方法后打印日志等)等功能. 使用动态代理的五大步骤 1.通过实现InvocationHandler接口来自定义自己的Invocati

  • 浅谈Java代理(jdk静态代理、动态代理和cglib动态代理)

    一.代理是Java常用的设计模式,代理类通过调用被代理类的相关方法,并对相关方法进行增强.加入一些非业务性代码,比如事务.日志.报警发邮件等操作. 二.jdk静态代理 1.业务接口 /** * 业务接口 * @author pc * */ public interface UserService { // 增加一个用户 public void addUser(); // 编辑账户 public void editUser(); } 2.业务实现类 /** * 业务实现类 * @author pc

  • Java JDK动态代理的基本原理详细介绍

    JDK动态代理详解 本文主要介绍JDK动态代理的基本原理,让大家更深刻的理解JDK Proxy,知其然知其所以然.明白JDK动态代理真正的原理及其生成的过程,我们以后写JDK Proxy可以不用去查demo,就可以徒手写个完美的Proxy.下面首先来个简单的Demo,后续的分析过程都依赖这个Demo去介绍,例子采用JDK1.8运行. JDK Proxy HelloWorld package com.yao.proxy; /** * Created by robin */ public inter

  • 深入理解java动态代理的两种实现方式(JDK/Cglib)

    什么是代理模式? 代理模式:在调用处不直接调用目标类进行操作,而是调用代理类,然后通过代理类来调用目标类进行操作.在代理类调用目标类的前后可以添加一些预处理和后处理操作来完成一些不属于目标类的功能. 为什么要使用代理模式? 通过代理模式可以实现对目标类调用的控制.在目标类调用前/后进行一些不属于目标类的操作,如:数据验证.预处理.后处理.异常处理等 什么是静态代理什么是动态代理? 静态代理:代理类只能实现对"特定接口的实现类"进行代理 动态代理:代理类可以实现对多种类的代理 jdk代理

  • java jdk动态代理详解

    jdk动态代理要对一个类进行代理,被代理的类必须实现至少一个接口,并且只有接口中的方法才能被代理. jdk实现动态代理一般分为三步: 1. 编写接口和实现类. 2. 写一个处理器,该处理器实现InvocationHandler接口,该接口只有一个方法,其签名为public Object invoke(Object proxy, Method method, Object[] args)throws Throwable;可在该处理器的实现方法中,在方法调用前和调用后加入自己的代码,从而进行动态拦截

  • java代理 jdk动态代理应用案列

    java代理有jdk动态代理.cglib代理,这里只说下jdk动态代理,jdk动态代理主要使用的是java反射机制(既java.lang.reflect包) 原理是(歌手.经纪人做例子): 建立一个公共的接口,比如:歌手public interface Singer: 用具体的类实现接口,比如:周杰伦,他是歌手所以实现Singer这个类,class MySinger implements Singer 建立代理类,这里也就是经纪人,他需要实现InvocationHandler类,并重写invok

  • Java JDK 动态代理的使用方法示例

    本文主要和大家分享介绍了关于Java JDK 动态代理使用的相关内容,分享出来供大家参考学习,下面来一起看看详细的介绍: 前言 代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问.代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理. Spring AOP的实现对于接口来说就是使用的JDK的动态代理来实现的,而对于类的代理使用CGLIB来实现. JDK的动态代理,就是在程序运行的过程中,根据被代理的接口来动态生成代理类的class文

  • java 中动态代理(JDK,cglib)实例代码

    java 动态代理实例详解 1.jdk动态代理 /** * */ package com.sinosoft; /** *接口:编写一个委托类的接口,即静态代理的(Apple接口) * */ public interface Apple { public void phoneCall(); } /** * */ package com.sinosoft; /** * 实现一个真正的委托类,即静态代理的(AppleImpl类) * */ public class AppleImpl implemen

随机推荐