Spring Aop 的底层生成代理类i的实现除 jdk的动态代理技术外,还用到了Cglib,不过在封装两者的设计原理上相差不大,只是底层工具不同而已。

本文只分析JdkDynamicAopProxy 是如何为一个目标方法执行织入多个切点,也就是将原本可能需要多个“代理类“实现的业务放到一个代理类中(JdkDynamicAopProxy)完成。

JdkDynamicAopProxy 本身就是一个JDK代理的InvocationHandler,spring 在调用其getProxy()方法返回一个代理类对象时:

public Object getProxy(ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
}
Class[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); 传入的 Handler 就是this,也就是 一个 JdkDynamicAopProxy 对象。所以代理的业务就在 JdkDynamicAopProxy
invoke()方法上。
 /**
* Implementation of <code>InvocationHandler.invoke</code>.
* <p>Callers will see exactly the exception thrown by the target,
* unless a hook method throws an exception.
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation;
Object oldProxy = null;
boolean setProxyContext = false; TargetSource targetSource = this.advised.targetSource;
Class targetClass = null;
Object target = null; try {
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
return hashCode();
}
if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// Service invocations on ProxyConfig with the proxy config...
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
} Object retVal; if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
} // May be null. Get as late as possible to minimize the time we "own" the target,
// in case it comes from a pool.
target = targetSource.getTarget();
if (target != null) {
targetClass = target.getClass();
} // Get the interception chain for this method.
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

// Check whether we have any advice. If we don't, we can fallback on direct
// reflective invocation of the target, and avoid creating a MethodInvocation.
if (chain.isEmpty()) {
// We can skip creating a MethodInvocation: just invoke the target directly
// Note that the final invoker must be an InvokerInterceptor so we know it does
// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
}
else {
// We need to create a method invocation...
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
retVal = invocation.proceed();
} // Massage return value if necessary.
if (retVal != null && retVal == target && method.getReturnType().isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// Special case: it returned "this" and the return type of the method
// is type-compatible. Note that we can't help if the target sets
// a reference to itself in another returned object.
retVal = proxy;
}
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
// Must have come from TargetSource.
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
invoke方法中的红色加粗代码就是重点部分:

List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); 
该行代码是构建代理链,获取到目标方法需要增强的一系列业务代理对象。
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
通过将目标方法和 多个业务代理对象 创建成一个
ReflectiveMethodInvocation,来实际完成 执行目标方法时执行一些拦截器,也就是代理业务。 retVal = invocation.proceed();
该行代码开始执行代理业务和目标方法。 下面是ReflectiveMethodInvocation 的 proceed方法代码:
 public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
} Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
return proceed();
}
}
else {
// It's an interceptor, so we just invoke it: The pointcut will have
// been evaluated statically before this object was constructed.
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}

可以看到proceed()方法通过从interceptorsAndDynamicMethodMatchers(list)集合中取出拦截器,拦截器是在前面创建ReflectiveMethodInvocation对象时传入的chain,

通过判断拦截器集合中所有拦截器是否执行完,未执行完这递归调用proceed()方法,执行完则执行目标方法。

以上就是JdkDynamicAopProxy实现多个拦截器拦截目标方法的动态代理业务。


 
 
 


最新文章

  1. 解读ASP.NET 5 &amp; MVC6系列(15):MvcOptions配置
  2. BZOJ1798: [Ahoi2009]Seq 维护序列seq[线段树]
  3. asp.net 琐记
  4. UVa11082 Matrix Decompressing(最小费用最大流)
  5. 简单Qt网络通信
  6. 有空可以对C#尝一下鲜,WCF看上去很诱人(跨进程、跨机器、跨子网,跨企业网乃至跨Internet的分布式服务)
  7. #ifndef #define #endif 防止头文件被重复引用
  8. C++ 对象的内存布局(上)
  9. 格式化格林威治时间(Wed Aug 01 00:00:00 CST 2012)
  10. Visual Studio 中指定自定义生成事件
  11. python抓取zabbix图形,并发送邮件
  12. 在高并发、高负载的情况下,如何给表添加字段并设置DEFAULT值?
  13. 常用的TCP选项
  14. JS/jquery实现鼠标控制页面元素显隐
  15. tomcat错误The superclass &quot;javax.servlet.http.HttpServlet&quot; was not found on the Java Build Path
  16. css修改整个项目的滚动条样式
  17. pyqt------对话框
  18. 金融量化分析【day113】:PGEC策略
  19. JavaScript -- Window-Confirm
  20. 使用再生龙Clonezilla备份还原Linux系统

热门文章

  1. C/C++/Linux编程经典电子书pdf下载
  2. Gradle: 一个诡异的问题(ERROR: Failed to parse XML AndroidManifest.xml ParseError at [row,col]:[5,5] Message: expected start or end tag)
  3. Xcode: Xcode中Command Line Tools的安装方法
  4. 002 elasticsearch中的一些概念
  5. #软件更新#Visual Studio更新到16.3.8
  6. failure during conversion to COFF:file invalid or corrupt
  7. ISO/IEC 9899:2011 条款6.7.6——声明符
  8. LeetCode_219. Contains Duplicate II
  9. html5 横向滑动导航栏
  10. CentOS8安装docker