动态代理

150 阅读3分钟

动态代理的作用

动态代理动态生成代理对象的class,反射得到代理对象,,并传入代理回调类,达到在调用被代理对象方法调用之前插入自己的代码逻辑,比如插入日志,增加一些控制等等。结合注解技术,非常适合做面向切面编程。

动态代理的四要素

  • 1.被代理对象
  • 2.被代理接口
  • 3.代理方法的回调
  • 4.动态代理关联

动态代理的例子

  • 1.被代理对象

它是实际业务的实现者

public class IOCImpl implements IOCInterface{
    @Override
    public void buy() {
        System.out.println("buy goods ");
    }

    @Override
    public boolean play(String player) {
        System.out.println(player + " is playing ");
        return true;
    }

    public void noImpl(){
        System.out.println(" no impl is called ");
    }
}
  • 2.被代理的接口

确定要代理的方法,例如对于onImpl可以不做代理

/**
 * 被代理的接口
 */
public interface IOCInterface {
    void buy();
    boolean play(String player);
}
  • 3.代理方法回调

这个回调类持有了被代理的对象,通过构造方法传入。任何对于被代理对象的调用都会回调给invoke方法,在invoke中的三个参数 proxy是代理对象,method是调用的被代理对象的方法,args为调用参数。

在invoke中,我们通过调用被代理对象本身的方法,来做真实的业务method.invoke(object , args);这里的object不是proxy,而是真实的被代理对象

public class IOCInvocationHandler implements InvocationHandler {

    Object object;
    IOCInvocationHandler(Object object){
        this.object = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before call ...." + method.getName() + "  " + proxy.getClass());
        Object obj = method.invoke(object , args);
        System.out.println("after call ....");

        return obj;
    }
}
  • 4.动态代理关联

把代理对象与被代理对象关联起来,达到代理的目的,这里的重点是将被代理对象ioc,传入到IOCInvocationHandler中,从而实现关联

IOCImpl ioc = new IOCImpl();
IOCInterface iocInterface = (IOCInterface) Proxy.newProxyInstance(
        IOCInterface.class.getClassLoader()
        , new Class[]{IOCInterface.class}
        , new IOCInvocationHandler(ioc));
iocInterface.buy();
iocInterface.play("Lucy");

动态代理的原理

Proxy.newProxyInstance的实现简化版

public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) {
    final Class<?>[] intfs = interfaces.clone();
    Class<?> cl = getProxyClass0(loader, intfs);

    final Constructor<?> cons = cl.getConstructor(constructorParams);
    final InvocationHandler ih = h;
    if (!Modifier.isPublic(cl.getModifiers())) {
        cons.setAccessible(true);
    }
    return cons.newInstance(new Object[]{h});
}
  • 1.动态生成代理对象的class

生成代理对象的class

Class<?> cl = getProxyClass0(loader, intfs);

它最终会调用到ProxyClassFactory.apply()方法,这个方法做对输入的参数做一些检测,比如是不是代理的接口以及访问权限的处理

public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
    ...
    return generateProxy(proxyName, interfaces, loader, methodsArray,exceptionsArray);
}


@FastNative
private static native Class<?> generateProxy(String name, Class<?>[] interfaces,ClassLoader loader, Method[] methods,Class<?>[][] exceptions);

老版本会通过ProxyGenerator.generateProxyClass来生成代理对象的class文件,新版本修改后,通过native方法来实现,我们直接看新版本的实现。

实现类在java_lang_reflect_Proxy.cc中,它调用了class_linker 中的CreateProxyClass

static jclass Proxy_generateProxy(JNIEnv* env, jclass, jstring name, jobjectArray interfaces,
                                  jobject loader, jobjectArray methods, jobjectArray throws) {
  ScopedFastNativeObjectAccess soa(env);
  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
  return soa.AddLocalReference<jclass>(class_linker->CreateProxyClass(
      soa, name, interfaces, loader, methods, throws));
}

CreateProxyClass 的实现在class_linker.cc中,感兴趣的可以自己去看看。

  • 2.通过反射构造代理对象

在构造代理对象的时候,传入回调实现类InvocationHandler,这样在所有的调用被代理对象的方法都会调用InvocationHandler.invoke方法中,实现代理的目的。

cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
    cons.setAccessible(true);
}
return cons.newInstance(new Object[]{h});