动态代理的作用
动态代理动态生成代理对象的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});