简学Java
2019-09-04 16:12:39浏览 2326
Spring Aop中的动态代理
spring AOP的底层实现由俩种方式: 一种是JDK动态代理,另一种是CGLib动态代理。
区别主要是jdk是代理接口,而cglib是代理类。
动态代理的前世今生
自Java 1.3以后,Java提供了动态代理技术,允许开发者在运行期创建接口的代理实例,后来这项技术被用到了Spring的很多地方。
JDK动态代理主要涉及java.lang.reflect包下边的两个类:Proxy和InvocationHandler。其中,InvocationHandler是一个接口,可以通过实现该接口定义横切逻辑,并通过反射机制调用目标类的代码,动态地将横切逻辑和业务逻辑贬值在一起。
JDK动态代理的话,他有一个限制,就是它只能为接口创建代理实例,而对于没有通过接口定义业务方法的类,如何创建动态代理实例哪?答案就是CGLib。
CGLib采用底层的字节码技术,全称是:Code Generation Library,CGLib可以为一个类创建一个子类,在子类中采用方法拦截的技术拦截所有父类方法的调用并顺势织入横切逻辑。
JDK动态代理
JDK动态代理原理详解
- jdk的动态代理调用了Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) 方法。
- 通过该方法生成字节码,动态的创建了一个代理类,interfaces参数是该动态类所继承的所有接口,而继承InvocationHandler 接口的类则是实现在调用代理接口方法前后的具体逻辑,下边是具体的实现:
JDK动态代理的源码分析
public class JDKDynamicProxy implements InvocationHandler {
private Object targetObject;
public Object newProxy(Object targetObject) {
this.targetObject = targetObject;
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
targetObject.getClass().getInterfaces(), this);
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
before();
Object ret = null;
ret = method.invoke(targetObject, args);
after();
return ret;
}
private void before() {
System.out.println("方法执行前 !");
}
private void after() {
System.out.println("方法执行后");
}
}
CGLib动态代理
CGLib动态代理原理详解
- MethodProxy#invoke 对被调用的方法进行拦截
- CglibAopProxy.DynamicAdvisedInterceptor#intercept 实现CGLib的动态代理实现
AOP中CGLib动态代理的源码分析
package org.springframework.cglib.proxy;
public class MethodProxy {
public Object invoke(Object obj, Object[] args) throws Throwable {
try {
init();
FastClassInfo fci = fastClassInfo;
return fci.f1.invoke(fci.i1, obj, args);
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
catch (IllegalArgumentException ex) {
if (fastClassInfo.i1 < 0)
throw new IllegalArgumentException("Protected method: " + sig1);
throw ex;
}
}
}
package org.springframework.aop.framework;
class CglibAopProxy implements AopProxy, Serializable {
private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {
private final AdvisedSupport advised;
public DynamicAdvisedInterceptor(AdvisedSupport advised) {
this.advised = advised;
}
@Override
@Nullable
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Object target = null;
TargetSource targetSource = this.advised.getTargetSource();
try {
if (this.advised.exposeProxy) {
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = methodProxy.invoke(target, argsToUse);
}
else {
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
}
if (setProxyContext) {
AopContext.setCurrentProxy(oldProxy);
}
}
}
}
}