微信号:DianrongMafia

介绍:点融黑帮——一个充满激情和梦想的技术团队,吸引了来自金融及信息科技领域的顶尖人才.我们正在用技术创新改变传统金融.

浅析Spring AOP

2017-09-29 19:00 李威

本文大概:1200字阅读需要:15分钟


Aop(Aspect-OrientedProgramming)面向切面编程是对OOP的补充,专注于系统中不同模块统一的处理逻辑,比如事务管理,日志管理,缓存等系统级服务。


众所周知,SpringAop基于代理实现的,比如JDK动态代理和CGLIB代理。

既然如此,在这之前先初探JDK动态代理。


那么如何使用JDK动态代理呢?


1):创建实现了InvocationHandler接口的类,实现invoke方法,该方法将在与之关联的代理类方法调用的时候执行


2):通过Proxy.newProxyInstance()方法返回代理对象



target为需要代理的目标对象,一般实现了某个接口,本例中Pojo接口只有两个简单方法



SimplePojo实现了Pojo接口,当调用bar(),foo()方法时,最终会调用invoke方法,实现拦截的逻辑。



为什么最终会调用invoke方法呢?


主要原因还在于Proxy.newProxyInstance()返回了一个代理类,该类以$Proxy开头,并实现了目标对象所实现的接口,并把实现了InvocationHandler的类作为代理类的构造参数;


如上例子,会产生一个name为$Proxy0的类,同时实现了Pojo接口。



因此,从生成的class可以看出,当调用foo(),bar()方法时,最终会调用invoke方法,可以在目标方法的调用前后实现其他的业务逻辑。



分析完JDK动态代理,下面正式进入springAop的世界,对于如何使用AOP,本文不做过多的分析,并以注解的形式进行浅析。


以下申明了一个Aspect,当com.dr.demo包以及子包的对象(托管至spring容器)方法调用时,即会调用doAudit方法。


这一切又是怎么发生了呢?



整个过程大致分为四步:



1.注册Aop处理器


Spring容器在加载配置文件解析标签 时,会在spring-aop.jar包下的META-INF文件下找到spring.handlers的properties文件



该handler会注册针对 标签的解析器



其主要作用即向容器注入处理@Aspect注解的bean



AnnotationAwareAspectJAutoProxyCreator的类层次图如下图所示:



可以看出该类实现了BeanPostProcessor接口,Spring文档对该接口的解释即允许对bean进行修改,比如返回代理。



而Spring容器在初始化bean的时候会调用beanpost processor(bean的创建过程本文不做分析),本文最后附上了BeanPostProcessor的一个应用。


2.查找容器内所有的Advisors


该逻辑在AnnotationAwareAspectJAutoProxyCreator.findCadidateAdvisors()方法,其主要逻辑即是寻找容器中标有@Aspect注解的类以及配置文件中的



@Aspect的处理逻辑大概概括为:提取标有@Aspect注解类的方法(排除了标有@PonitCut注解的方法),对标记有@Aroud,@Before,@After,@AfterReturing,@AfterThrowing的方法封装为Advisor.并且返回的是有序的集合,顺序分别是@Around,@Before,@After,@AfterReturning,@AfterThrowing。此时即提取了所有的Advisor.


3.查找符合条件的bean


findAdvisorsThatCanApply的主要逻辑是寻找匹配当前bean的Advisor.从编码的角度来看,即当前bean匹配Advisor的切入点表达式;比如:execution(*com.dr.demo..*.*(..)),即com.dr.demo包以及其子包下的类的任何方法都应进行增强。



4.创建代理对象


前面第一点提到AnnotationAwareAspectJAutoProxyCreator实现了BeanProcessor接口,此处即对容器里符合条件的bean创建代理。



Spring提供2种方式实现代理:CGLIB代理以及JDK代理,比如设置了proxy-target-class,则会使用Cglib代理,本文以JDK动态代理为例,分析创建代理对象的过程。



本文开篇即分析了JDK动态代理原理,以及使用方式,看看spring又是如何实现呢?



JdkDynamicAopProxy同样实现了InvocationHandler,其getProxy方法返回代理对象,代理的接口即为第3步找到的Advisor.



因此,当从spring容器里获取对象时,其实质是返回的代理对象;当执行方法时,均会执行invoke方法,以下代码片段是invoke方法的一部分,封装拦截器链(不止一个增加),随后遍历拦截器链,执行拦截器方法,直到拦截器链执行完毕,在执行目标方法。



小结:以上只是对springaop粗略的分析,springaop的实现极为复杂,比如切入点表达的提取,以及joinPoint与PointCut的匹配等内容。


参考文献:

https://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#aop-introduction-defn


http://mp.weixin.qq.com/s?__biz=MjM5MDI3MjA5MQ==&mid=2697266477&idx=2&sn=984b552b462cd38ecd7b05339a1004c5&chksm=8376fa19b401730f2c03a5ad0abc43845d6009f6583bf2bf659b0a9c24654e46d577d98e5e56&mpshare=1&scene=1&srcid=0925YPKr7HMnM9XthTnyqG7z#rd





点击回顾往期精彩内容

香港金融科技周即将开启,点融成为钻石赞助商

Vue世界中的Redux——Vuex

点融荣登“中国网贷先锋榜”

Affordance杂谈

浅谈金融类APP测试

今天我们来谈谈信息收集这件小事

用Django编写后端任务流程

Webpack优化 | 快一点,再快一点

活动回顾 | CTDC2017首席技术官领袖峰会成功举办

今天我们来聊一聊运动这件事。

CSP与并发编程

使用 Mesos 管理 Docker 实践

来共享密钥吧

浅谈交易手续费设计#1

多Header or Footer的RecyclerViewAdapter

浅谈 golang channel



想了解更多请关注我们



 
点融黑帮 更多文章 香港金融科技周即将开启,点融成为钻石赞助商 什么? 这家互联网公司喊你来吃月饼啦? Vue世界中的Redux——Vuex 点融荣登“中国网贷先锋榜” Affordance杂谈
猜您喜欢 办公桌的故事 马云启动“NASA”计划 为未来20年愿景研发核心科技 Android仿小米巨无霸字体调整控件 时速云亮相GMIC2016,多重角色扮演受欢迎 伊隆.马斯克的快速学习方法