当前位置: 首页 > news >正文

Spring源码学习(二)------ AOP

AOP有些特有的概念,如:advisor、advice和pointcut等等,使用或配置起来有点绕,让人感觉有些距离感,其实它的实现就是一组标准的设计模式的组合使用:Factory、Proxy、Chain of Responsibility,只要搞清楚这几个设计模式,读AOP的源码是比较容易的。

首先看看ProxyFactoryBean这个类,这是AOP使用的入口,从AOP拿到的bean object就是ProxyFactoryBean.getObject得到的,从这条线下去,发现AOP就是通过Proxy模式从实际要执行的target做了包装,而Proxy还不止一套方案,通过Factory封装了两套Proxy实现方案:JDK 动态Proxy和Cglib Proxy。有两套实现主要是因为JDK 动态Proxy必须要target实现某个接口,如果不满足这个条件就会用Cglib增强字节码的方式来实现proxy。

就拿JDK Proxy为例,Spring AOP使用了标准的JDK提供的动态Proxy方案,我们先看看标准的动态Proxy是什么样子,看下面类图:

Cilent通过Proxy.newProxyInstance(classLoader, proxiedInterfaces, invocationHandler);就能拿到target的proxy object,在执行target的方法时就会先执行到DynamicProxy中的invoke方法从而实现代理包装。基于这个道理来看Spring AOP的实现,实际上就是标准地基于这个方式来做的,Spring AOP的所有花招都体现在JdkDynamicAopProxy.invoke中(当然在Cglib中是通过callback来做的,道理类似)。

通过看JdkDynamicAopProxy.invoke的源码会发现,Spring AOP的各种花招是通过Chain of Responsibility模式串起来的,先看看一个标准的Chain of Responsibility是什么样子,看下面的类图:

而Chain of Responsibility的关键在于Invocation与Interceptor的配合,主要原则就两条:

1)Invocation需要维护Interceptor集合和游标,每次调用invoke时需要先调用游标所在的Interceptor.invoke,如果游标已超过最后一个Interceptor,则调用实际target的方法

2)Interceptor的invoke中除了要执行自己的拦截逻辑,还要通过Invocation.invoke把调用传递下去,拦截的灵活性就体现在Invocation.invoke执行与否和执行的顺序。

以上逻辑通过时序图来看,如下图所示:

理解Chain of Responsibility后再来看Spring AOP,JdkDynamicAopProxy.invoke做的事情就是以上Client做的事情,

1)首先通过this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);组装interceptor chain

2)然后new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);得到invocation

3)最后通过invocation.proceed();启动责任链

而Spring AOP的那些概念都体现在组装interceptor chain中,advisor、advice和pointcut无非就是帮助你描述如何对Target进行拦截,对这一块感兴趣的朋友可以好好读读里面的代码。另外,Spring AOP提供了各种各样的Interceptor,来实现各种形式的横切,具体做法可以详细看看各Interceptor的实现。

综上所述,整个流程如下图所示:

总之,把握了Factory、Proxy、Chain of Responsibility的运用也就把握了Spring AOP的实现原理,道理虽然简单,但其中的精髓和原由还是值得我们继续深思的。

相关文章:

  • 2,3,4,11章
  • 职场官话
  • 团队项目冲刺第五天
  • 用borland together反向工程生成sequence图的方法
  • C字符数组的处理
  • p2p终结者破解版下载 4.15 2011最新版
  • mysql简单操作(实时更新)
  • 更新-清理sga组件
  • [BZOJ1178][Apio2009]CONVENTION会议中心
  • 20145302张薇《Java程序设计》第八周学习总结
  • QT(6)Basic Layout学习
  • EventSource
  • UTC时间转换为标准时间
  • 软件工程(二)可行性分析
  • OOM-KILLer的演进与新的启发式策略
  • C++类的相互关联
  • CentOS学习笔记 - 12. Nginx搭建Centos7.5远程repo
  • JavaScript的使用你知道几种?(上)
  • Spring Security中异常上抛机制及对于转型处理的一些感悟
  • uni-app项目数字滚动
  • webpack入门学习手记(二)
  • 从tcpdump抓包看TCP/IP协议
  • 分享几个不错的工具
  • 技术胖1-4季视频复习— (看视频笔记)
  • 日剧·日综资源集合(建议收藏)
  • 如何邀请好友注册您的网站(模拟百度网盘)
  • 微信开源mars源码分析1—上层samples分析
  • 云大使推广中的常见热门问题
  • ​什么是bug?bug的源头在哪里?
  • # 日期待t_最值得等的SUV奥迪Q9:空间比MPV还大,或搭4.0T,香
  • #大学#套接字
  • (9)目标检测_SSD的原理
  • (Mirage系列之二)VMware Horizon Mirage的经典用户用例及真实案例分析
  • (动态规划)5. 最长回文子串 java解决
  • (附源码)springboot电竞专题网站 毕业设计 641314
  • (六)c52学习之旅-独立按键
  • (免费领源码)python#django#mysql公交线路查询系统85021- 计算机毕业设计项目选题推荐
  • .chm格式文件如何阅读
  • .NET Compact Framework 3.5 支持 WCF 的子集
  • .NET Core工程编译事件$(TargetDir)变量为空引发的思考
  • .Net IOC框架入门之一 Unity
  • .NET 线程 Thread 进程 Process、线程池 pool、Invoke、begininvoke、异步回调
  • .net 写了一个支持重试、熔断和超时策略的 HttpClient 实例池
  • .NET 自定义中间件 判断是否存在 AllowAnonymousAttribute 特性 来判断是否需要身份验证
  • .net流程开发平台的一些难点(1)
  • .Net组件程序设计之线程、并发管理(一)
  • .pop ----remove 删除
  • @param注解什么意思_9000字,通俗易懂的讲解下Java注解
  • [ JavaScript ] JSON方法
  • []串口通信 零星笔记
  • [2019.2.28]BZOJ4033 [HAOI2015]树上染色
  • [AutoSar]状态管理(五)Dcm与BswM、EcuM的复位实现
  • [C#]科学计数法(scientific notation)显示为正常数字
  • [C#]使用DlibDotNet人脸检测人脸68特征点识别人脸5特征点识别人脸对齐人脸比对FaceMesh
  • [DAU-FI Net开源 | Dual Attention UNet+特征融合+Sobel和Canny等算子解决语义分割痛点]