动态代理(dynamic proxy)概念

利用Java的反射技术(Java Reflection),在运行时创建一个实现某些给定接口的新类(也称“动态代理类”)及其实例(对象),代理的是接口(Interfaces),不是类(Class),也不是抽象类。在运行时才知道具体的实现,spring aop就是此原理。

  1. public static Object newProxyInstance(ClassLoader loader,
  2. Class<?>[] interfaces,
  3. InvocationHandler handerler)
  4. throws IllegalArgumentException

newProxyInstance,方法有三个参数:

  1. loader: 用哪个类加载器去加载代理对象
  2. interfaces:动态代理类需要实现的接口
  3. handler:动态代理方法在执行时,会调用handler里面的invoke方法去执行

    实例

    被代理对象

    假设我们有一个被代理对象如下:
    public interface IVehical {void run();}
    
    public class Car implements IVehical {
    public void run() {        
     System.out.println("Car会跑");
    }
    }
    

那么我们执行如下的程序:

public class App {
  public static void main(String[] args) {
    IVehical car = new Car();
    vehical.run();    
  }
}

想必大家也知道结果是打印“Car会跑”

动态代理

现在我们要对被代理对象进行扩展,又不改变其原有代码,符合开闭原则,我们使用如下方法:

实现调用处理类invocationhandler

public class VehicalInvacationHandler implements InvocationHandler {
  private final IVehical vehical;
  VehicalInvacationHandler(IVehical vehical){
    this.vehical = vehical;    
  }

  @override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    System.out.println("---------before-------");
    Object invoke = method.invoke(vehical, args);
    System.out.println("---------after-------");
    return invoke;    
  }
}

我们发现这个处理类由三部分构成:

  1. 私有的成员变量:被代理对象
  2. 带有参数的构造方法,传入被代理对象的实例
  3. 重写invoke方法:代理对象(如下面的vehical)在执行时代理方法时(如下面的run)需要动态传入:代理对象、代理的方法、执行的参数
public class App {
  public static void main(String[] args) {
    IVehical car = new Car();
    IVehical vehical = (IVehical)Proxy.newProxyInstance(car.getClass().getClassLoader(),
                                                        Car.class.getInterfaces(),
                                                        new VehicalInvacationHandler(car));
    vehical.run();    
  }
}

上面代码中,代理car对象,调用run方法时,自动执行invocationhandler中的invoke方法。

【2】动态代理 - 图1

可以打印一下:

 System.out.println(vehical.getClass());

【2】动态代理 - 图2
可以看出现在的vehical实例并不是一个真正的vehical实例,而实其代理对象。我们一起来看一看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);
        }
    }