动态代理入门学习笔记

动态代理实现的两种方式:
jdk内置动态代理
cglib

jdk内置:

在java.lang.reflect包下有一个工具类:

Proxy存在一个方法:

 @CallerSensitive
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h) throws IllegalArgumentException{

ClassLoader: 类加载器 传入的就是原有对象的类加载器,原有对象.getClass().getClassLoader();
interfaces: 接口数组 传入原有对象实现的所有接口 原有对象.getClass().getinterfaces();
invocationHandler: 执行处理类对象
可以看一下源码:

public interface InvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}

它是一个接口,只有一个invoke方法

proxy: 代理对象
method: 增强对象在调用方法的时候的方法本身
args: 增强对象调用方法的时候传入的实参数组本身.

可能不太好理解,直接用代码来演示一下:
定义接口car:

public interface Car {

    void run();
    void stop();
    int oilTank();   //油箱大小

    void driver(String diverName);

    Car didi();
}

qq车实现类:

public class QQ implements Car {
    @Override
    public void run() {
        try {
            Thread.sleep(1000);
            System.out.println("qq完成百公里加速");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void stop() {
        System.out.println("刹车");
    }

    @Override
    public int oilTank() {
        return 50;
    }

    @Override
    public void driver(String diverName) {
        System.out.println(diverName+"正在驾驶中");
    }

    @Override
    public Car didi() {
        System.out.println("按喇叭");
        return this;
    }
}

此时我想获取qq完成百公里加速花费的时间,通过动态代理:

/**
 * 动态代理实现
 */
public class ProxyTest2 {

    public static void main(String[] args) {
        QQ qq = new QQ();

        Car car =(Car)Proxy.newProxyInstance(
                qq.getClass().getClassLoader(),
                qq.getClass().getInterfaces(),
                new ZQHandler(qq));

        car.run();
        car.stop();
        car.driver("小明");
        int i = car.oilTank();
        System.out.println(i);
        car.didi();

    }

    private static class ZQHandler implements InvocationHandler{

        private  Car car;

        public ZQHandler(Car car){
            this.car = car;
        }
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {



          // method.invoke(car);
            //当前方法名称
            System.out.println(method.getName());
            //当前方法名称为run时则进行增强
            if ("run".equals(method.getName())){
                long start = System.currentTimeMillis();
                //调用原有方法
                method.invoke(car);
                long end = System.currentTimeMillis();
                System.out.println("花费时间: " + (end-start));

            }else if("driver".equals(method.getName())){

                System.out.println(args[0]);
                method.invoke(car,"小红");



            }else if("oilTank".equals(method.getName())){

                Object o = method.invoke(car);

                return (Integer)o+50;


            }else if("didi".equals(method.getName())){
                method.invoke(car);

                //返回增强对象
                return proxy;

            }else {
                //调用原有方法
                method.invoke(car);
            }

            return null;
        }
    }
}

输出结果:
在这里插入图片描述
根据结果可以看出不仅仅可以针对逻辑增强,对参数和返回值都可以进行增强.

实现原理:

我们先使用ProxyGenerator对象通过Car接口生成一个class文件存入到本地,稍后会提到为什么会说到ProxyGenerator对象

public class ProxyTest {


    public static void main(String[] args) throws IOException {
        byte[] xes = ProxyGenerator.generateProxyClass("X", new Class[]{Car.class});

        FileOutputStream fileOutputStream = new FileOutputStream("D:\\X.class");


        fileOutputStream.write(xes);
    }
}

在本地用java反编译工具打开class文件:

import com.ceeemall.aop.service.Car;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class X extends Proxy
  implements Car
{
  private static Method m1;
  private static Method m6;
  private static Method m3;
  private static Method m2;
  private static Method m4;
  private static Method m5;
  private static Method m7;
  private static Method m0;

  public X(InvocationHandler paramInvocationHandler)
    throws 
  {
    super(paramInvocationHandler);
  }

  public final boolean equals(Object paramObject)
    throws 
  {
    try
    {
      return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  public final Car didi()
    throws 
  {
    try
    {
      return (Car)this.h.invoke(this, m6, null);
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  public final void run()
    throws 
  {
    try
    {
      this.h.invoke(this, m3, null);
      return;
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  public final String toString()
    throws 
  {
    try
    {
      return (String)this.h.invoke(this, m2, null);
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  public final void stop()
    throws 
  {
    try
    {
      this.h.invoke(this, m4, null);
      return;
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  public final int oilTank()
    throws 
  {
    try
    {
      return ((Integer)this.h.invoke(this, m5, null)).intValue();
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  public final void driver(String paramString)
    throws 
  {
    try
    {
      this.h.invoke(this, m7, new Object[] { paramString });
      return;
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  public final int hashCode()
    throws 
  {
    try
    {
      return ((Integer)this.h.invoke(this, m0, null)).intValue();
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  static
  {
    try
    {
      m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
      m6 = Class.forName("com.ceeemall.aop.service.Car").getMethod("didi", new Class[0]);
      m3 = Class.forName("com.ceeemall.aop.service.Car").getMethod("run", new Class[0]);
      m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
      m4 = Class.forName("com.ceeemall.aop.service.Car").getMethod("stop", new Class[0]);
      m5 = Class.forName("com.ceeemall.aop.service.Car").getMethod("oilTank", new Class[0]);
      m7 = Class.forName("com.ceeemall.aop.service.Car").getMethod("driver", new Class[] { Class.forName("java.lang.String") });
      m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
      return;
    }
    catch (NoSuchMethodException localNoSuchMethodException)
    {
      throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
    }
    catch (ClassNotFoundException localClassNotFoundException)
    {
      throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
    }
  }
}

首先是可以看到生成的类继承了Proxy类实现了我们的Car接口,因此生成的X类中必定是实现了Car中的所有方法.
比如我们可以看到run方法,

 public final void run()
    throws 
  {
    try
    {
      this.h.invoke(this, m3, null);
      return;
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

这个h是父类Proxy中的,指的是invocationHandler接口,因为是protected修饰,因此在子类通过this可以访问:

  /**
     * the invocation handler for this proxy instance.
     * @serial
     */
    protected InvocationHandler h;

/**
     * Constructs a new {@code Proxy} instance from a subclass
     * (typically, a dynamic proxy class) with the specified value
     * for its invocation handler.
     *
     * @param  h the invocation handler for this proxy instance
     *
     * @throws NullPointerException if the given invocation handler, {@code h},
     *         is {@code null}.
     */
    protected Proxy(InvocationHandler h) {
        Objects.requireNonNull(h);
        this.h = h;
    }

再往下看可以看到对静态变量m的定义:

 static
  {
    try
    {
      m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
      m6 = Class.forName("com.ceeemall.aop.service.Car").getMethod("didi", new Class[0]);
      m3 = Class.forName("com.ceeemall.aop.service.Car").getMethod("run", new Class[0]);
      m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
      m4 = Class.forName("com.ceeemall.aop.service.Car").getMethod("stop", new Class[0]);
      m5 = Class.forName("com.ceeemall.aop.service.Car").getMethod("oilTank", new Class[0]);
      m7 = Class.forName("com.ceeemall.aop.service.Car").getMethod("driver", new Class[] { Class.forName("java.lang.String") });
      m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
      return;
    }
    catch (NoSuchMethodException localNoSuchMethodException)
    {
      throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
    }
    catch (ClassNotFoundException localClassNotFoundException)
    {
      throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
    }
  }

通过反射获取Car接口中所有的方法.

这样步骤就比较清晰了, 生成的类X我们可以理解为代理类,他实现了原有类实现的接口Car,同时继承了Proxy,代理类通过父类Proxy的成员变量InvocationHandler,调用其invoke方法,而invoke需要三个参数,proxy就是代理对象本身,传入的是this,method代表需要增强方法的本身,如我需要执行run(); 则method就是run()方法对象,即m3, args则为参数数据,run()没有参数则为null

然后我们再来看一下Proxy中newProxyInstance做了什么事情:

@CallerSensitive
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        Objects.requireNonNull(h);

        final Class<?>[] intfs = interfaces.clone();
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }

        /*
         * Look up or generate the designated proxy class.
         */
        Class<?> cl = getProxyClass0(loader, intfs);

        /*
         * Invoke its constructor with the designated invocation handler.
         */
        try {
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }

            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
            return cons.newInstance(new Object[]{h});
        } catch (IllegalAccessException|InstantiationException e) {
            throw new InternalError(e.toString(), e);
        } catch (InvocationTargetException e) {
            Throwable t = e.getCause();
            if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            } else {
                throw new InternalError(t.toString(), t);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString(), e);
        }
    }

先挑几步重点来看:
final Class<?>[] intfs = interfaces.clone(); 克隆了实现的接口

Class<?> cl = getProxyClass0(loader, intfs); //获取代理对象

final Constructor<?> cons = cl.getConstructor(constructorParams); //获取代理对象的构造器

return cons.newInstance(new Object[]{h}); //通过构造方法创建实例,invocationHandler的数组为参数

点进getProxyClass0(loader, intfs);,多点几次点到apply();
前面是一系列的判断 + 类名及路径的拼接
然后有这样一行代码:

 byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces, accessFlags);
            try {
                return defineClass0(loader, proxyName,
                                    proxyClassFile, 0, proxyClassFile.length);
            } catch (ClassFormatError e) {
                /*
                 * A ClassFormatError here means that (barring bugs in the
                 * proxy class generation code) there was some other
                 * invalid aspect of the arguments supplied to the proxy
                 * class creation (such as virtual machine limitations
                 * exceeded).
                 */
                throw new IllegalArgumentException(e.toString());
            }

就是通过ProxyGenerator对象创建代理对象的.后面的defineClass0()方法是将字节数组转化成class对象的操作,就不看了,因为我也看不懂.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值