什么是动态代理?
以下为个人理解:
动态代理就是在程序运行的期间,动态地针对对象的方法进行增强操作。并且这个动作的执行者已经不是"this"对象了,而是我们创建的代理对象,这个代理对象就是类似中间人的角色,帮助我们为目标方法嵌入一些其他的逻辑进去。
jdk动态代理的原理
jdk自带的动态代理的工作原理是利用反射的newInstance,创建一个代理对象(proxy),获取到目标接口的方法,然后我们就可以在Invoke之前或之后做操作。它抽取出了一个invokeHandler,里面就有目标method。
试想一下,当我们拥有了class对象,增强逻辑(invokeHandler),也就是增强的目标方法之后,我们自己利用反射(不利用Proxy)也可以很容易写出我们自己的动态代理。但是问题就在于,我们只有明确了目标类之后,通过自己编写Proxy类,实现目标接口,往里面塞invoktionHandler, 最后New出来这个实实在在的对象。而jdk提供的动态代理,却可以在并不知情的情况下,帮我们做这一系列的动作。
jdk生成代理类时,并没有经历源码阶段,编译阶段,而是直接到字节码阶段,它生成的代理类是看不到的,因为它直接就是字节码文件了。 它帮我们继承了Proxy类,并且还动态的帮助我们继承了目标接口。也就是说,它帮我们写代码了。里面用到的技术,是ASM技术,它可以直接生成我们想要的字节码。
jdk方法反射调用优化:
invoke() 利用反射进行本地调用,效率低下,它在调用了一定的次数(16)之后会生成实例化对象,变成正常调用。
InvocationHandler接口
publicinterfaceInvocationHandler {
publicObjectinvoke(Objectproxy, Methodmethod, Object[] args)throwsThrowable;
}
源码
@CallerSensitive
publicstaticObjectnewProxyInstance(ClassLoaderloader,
Class<?>[] interfaces,
InvocationHandlerh)
throwsIllegalArgumentException
{
Objects.requireNonNull(h);
finalClass<?>[] intfs=interfaces.clone();
finalSecurityManagersm=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);
}
finalConstructor<?>cons=cl.getConstructor(constructorParams);
finalInvocationHandlerih=h;
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(newPrivilegedAction<Void>() {
publicVoidrun() {
cons.setAccessible(true);
returnnull;
}
});
}
returncons.newInstance(newObject[]{h});
} catch (IllegalAccessException|InstantiationExceptione) {
thrownewInternalError(e.toString(), e);
} catch (InvocationTargetExceptione) {
Throwablet=e.getCause();
if (tinstanceofRuntimeException) {
throw (RuntimeException) t;
} else {
thrownewInternalError(t.toString(), t);
}
} catch (NoSuchMethodExceptione) {
thrownewInternalError(e.toString(), e);
}
}
cglib动态代理的原理
cglib动态代理的原理跟jdk的类似,只不过它是基于父类继承,也就是不需要实现接口就可以做增强。它的内部并不是InvoktionHandler,而是方法拦截器 MethodInterceptor 。
前面的jdk动态代理,它是利用ASM技术帮我们动态编写了一个proxy对象,其中继承了Proxy父类,实现了目标接口,而cglib则是利用ASM直接帮助我们继承了目标类,不需要接口。
并且有所区别的是,它不仅仅通过反射拿到method,还拿到了MethodProxy。
MethodInterceptor接口 继承了Callback接口,它的拦截方法里面有一个特殊的参数 MethodProxy,这玩意可以不通过反射调用方法,通过invokeSuper() 方法可以直接正常调用。
MethodProxy是怎么做到正常调用的?
其实就是我们前面提到的,继承了Proxy父类之后,就得到了父类的原始方法,当我调用invokeSuper的时候,直接调用的就是父类的原始方法。
MethodInterceptor
publicinterfaceMethodInterceptorextendsCallback {
Objectintercept(Objectvar1, Methodvar2, Object[] var3, MethodProxyvar4) throwsThrowable;
}
MethodProxy
invoke() 无反射调用
invokeSuper() 无反射调用
publicObjectinvoke(Objectobj, Object[] args) throwsThrowable {
try {
this.init();
MethodProxy.FastClassInfofci=this.fastClassInfo;
returnfci.f1.invoke(fci.i1, obj, args);
} catch (InvocationTargetExceptionvar4) {
throwvar4.getTargetException();
} catch (IllegalArgumentExceptionvar5) {
if (this.fastClassInfo.i1<0) {
thrownewIllegalArgumentException("Protected method: "+this.sig1);
} else {
throwvar5;
}
}
}
publicObjectinvokeSuper(Objectobj, Object[] args) throwsThrowable {
try {
this.init();
MethodProxy.FastClassInfofci=this.fastClassInfo;
returnfci.f2.invoke(fci.i2, obj, args);
} catch (InvocationTargetExceptionvar4) {
throwvar4.getTargetException();
}
}