Spring AOP的实现及源码解析
在介绍AOP之前,想必很多人都听说AOP是基于动态代理和反射来实现的,那么在看AOP之前,你需要弄懂什么是动态代理和反射及它们又是如何实现的。
想了解JDK的动态代理及反射的实现和源码分析,请参见下面三篇文章
那么接下里进入AOP的环节。
AOP即面向切面编程,刚学AOP的时候,单是各种AOP的概念都搞的有点懵,什么切面,切点,通知,织入、连接点、目标对象。。。。AOP的原理都没看呢,这些词语的意思就已经让人不想看了。本文将在实现AOP的时候,讲解我理解的这些AOP的术语,对应的AOP的代码和动作。
本文将先从AOP代码实现入手,然后分析AOP的底层代码及其原理。
一、AOP的Demo
如果我们把对象的继承关系看成纵向关系,就像一棵树,多个不同类的多个继承关系就相当于有一排的树。AOP的好处就在于,你想对这些树进行相同的操作时,这个时候,不用纵向的为每个树定义操作方法,你只需要横向的一刀切,给他们提供个共有的操作方法。
Spring的AOP是支持JDK的动态代理和Cglib的动态代理的。JDK的动态代理是针对接口的,而Cglib是针对类的。本文针对JDK的动态代理。
首先定义一个接口:起名字时候特意给这个接口名,带上了Interface,这样后面会更引人注意一些。接口很简单,里面一个抽象方法eat()
package com.weili.cn;
/**
* 动物接口,提供一个eat的抽象方法
* Created by zsqweilai on 17/6/27.
*/
public interface AnimalInterface {
public abstract void eat();
}
实现类:作为一个吃货,实现类里面当然得打印 chi chi chi。撑死我吧!!!
这个实现类里面,只有一个方法,这个方法就是AOP的切点。虽然切点这个概念本身并不一定是Method,但在Spring中,所有的切点都是Method。我们增强的是方法。
切面类,又称增强类。因为我们是要用这个类的方法,来给原先的切点方法增强。切面类中,我们要去执行的方法,称为通知。所谓织入通知,就是将切面类里面的方法,和切点的方法进行联系。
接下来通过xml配置的方式,在xml文件里面配置AOP。
配置<aop:pointcut>的时候,通过expressi表达式,定义了com.weili.cn这个包下的所有类的所有方法 为切入点。也就是说,这个包下的所有方法,在调用执行的时候,会被Spring增强。具体在这里的增强,就是在执行这些切点方法之前和之后,会分别执行animalEmpty 和 animalFull方法。
最后就是调用的方法了。
我得说明一点,在我们进行spring-aop.xml解析的时候,aop还没实现呢。在第二行getBean的时候,才真正进行aop。具体的源码那里 会说明。
紧接着就是Output输出了。所以,我们可以看到,获取的bean,确实是增强后的bean。那么就赶紧看看源码吧。
二、AOP源码分析
源码解析这块,首先就是bean加载。之前也说了,AOP标签也是自定义标签,它的解析也和我们之前自定义标签一样,走自定义标签的解析流程。不同的是,AOP调用的是AOP自己的解析器。由于在 Spring源码解析之二 ------ 自定义标签的解析和注册 中已经很详细的描述了自定义标签的解析流程,所以这里我们就不再去一一看bean标签的解析注册。
所以AOP的源码分析,我们将从调用类里面的第二行,ctx.getBean("animal")开始。在你调试走到这里的时候,在ctx中可以看到解析和注册的bean,我们不妨先来看一下。
如下图,这个是在第一行代码执行完毕后,ctx的各个属性。可以在下图看到,singlentonObjects中,已经存放了代理生成的animal。生层bean的过程在之前的里面已经讲的比较清楚了,这里就不再说明。毕竟AOP嘛,我们需要知道,它是如何在我们需要执行的方法前后将我们需要执行的方法执行完成的。
ctx.getBean("animal")获取完animal bean后,接下来调用eat()方法。这个时候,会进入JdkDynamicAopProxy类的invoke方法。
在这个invoke方法中,先是获取代理类targetClass,然后根据method和targetClass获取此方法对应的拦截器执行链chain。
这个chain的内容如下。通过名字可以看到,一个是afterAdvice,一个是beforeAdvice。获取chain后,构造出一个MethodInvoke方法,然后执行proceed方法。
进入proceed方法。currentInterceptorIndex的初始化值为-1.紧接着就如invoke方法。这里的this是我们的eat方法。
在invoke方法里,这里的mi是我们的interface里面的eat方法。然后执行mi的proceed()方法。
这个时候,会继续回到开始时候的proceed方法。这个时候获取到的是
interceptorOrInterceptionAdvice,也就是前面拦截器的list里面的第二个,after的那个方法。然后继续递归调用,会到链表的最后一个before方法。
最终会调用before里面的方法,
然后回去执行invokeJoinpoint方法,
Spring AOP的实现及源码解析的更多相关文章
- Spring核心框架 - AOP的原理及源码解析
一.AOP的体系结构 如下图所示:(引自AOP联盟) 层次3语言和开发环境:基础是指待增加对象或者目标对象:切面通常包括对于基础的增加应用:配置是指AOP体系中提供的配置环境或者编织配置,通过该配置A ...
- Spring MVC工作原理及源码解析(三) HandlerMapping和HandlerAdapter实现原理及源码解析
1.HandlerMapping实现原理及源码解析 在前面讲解Spring MVC工作流程的时候我们说过,前端控制器收到请求后会调⽤处理器映射器(HandlerMapping),处理器映射器根据请求U ...
- Spring IOC和Spring AOP的实现原理(源码主线流程)
写在前面 正本文参考了<spring技术内幕>和spring 4.0.5源码.本文只描述原理流程的主线部分,其他比如验证,缓存什么可以具体参考源码理解. Spring IOC 一.容器初始 ...
- SpringBoot 源码解析 (八)----- Spring Boot 精髓:事务源码解析
本篇来讲一下SpringBoot是怎么自动开启事务的,我们先来回顾一下以前SSM中是如何使用事务的 SSM使用事务 导入JDBC依赖包 众所周知,凡是需要跟数据库打交道的,基本上都要添加jdbc的依赖 ...
- 【SSH进阶之路】Spring的IOC逐层深入——源码解析之IoC的根本BeanFactory(五)
我们前面的三篇博文,简单易懂的介绍了为什么要使用IOC[实例讲解](二).和Spring的IOC原理[通俗解释](三)以及依赖注入的两种常用实现类型(四),这些都是刚开始学习Spring IoC容器时 ...
- Spring MVC工作原理及源码解析(二)DispatcherServlet实现原理及源码解析
1.DispatcherServlet 处理流程 从上一篇文章中Spring MVC原理图中我们可以看出:DispatcherServlet 在 Spring MVC框架 中处于核心位置,它负责协调和 ...
- 【spring源码学习】spring的事务管理的源码解析
[一]spring事务管理(1)spring的事务管理,是基于aop动态代理实现的.对目标对象生成代理对象,加入事务管理的核心拦截器==>org.springframework.transact ...
- Spring MVC工作原理及源码解析(四) ViewResolver实现原理及源码解析
0.ViewResolver原理介绍 根据视图的名称将其解析为 View 类型的视图,如通过 ModelAndView 中的视图名称将其解析成 View,View 是用来渲染页面的,也就是将 Mode ...
- Spring事件监听机制源码解析
Spring事件监听器使用 1.Spring事件监听体系包括三个组件:事件.事件监听器,事件广播器. 事件:定义事件类型和事件源,需要继承ApplicationEvent. package com.y ...
随机推荐
- 最强Hibernate搭建文章(转)
Hibernate优势: 1.Hibernate对JDBC访问数据库的代码做了轻量级的封装,大大简化了数据访问的层的重复性代码,并却减少了内存消耗,加快了运行效率. 2.Hibernate是一个基于J ...
- VUE - 相对路径
background-image背景图片路径问题可以这样解决:1.先在data里面导入这张图片,例如: bg:require('./openIndexBG2.jpg')2 ...
- R语言-地图
1.maps包的map()函数 >map('world', fill = TRUE,col=heat.colors(10)) #世界地图 >map("state", i ...
- Linux jdk安装
Linux上一般会安装Open JDK,关于OpenJDK和JDK的区别:http://www.cnblogs.com/sxdcgaq8080/p/7487369.html 下面开始安装步骤: --- ...
- HDU2665 求区间第K大 主席树
题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=2665 代码: //#include<bits/stdc++.h> #include< ...
- Django_Form验证(一)
Django为我们提供了一个模板来做Form验证,不需要我们再去写复杂的验证代码了 简单的提交信息html页面: <form action="/fff/Form" metho ...
- oslo_messaging与rabbitmq
oslo_messaing通过kombu与rabbitmq建立channel连接,向rabbitmq中发送数据 在oslo_messaging/_drivers/impl_rabbit.py中,初始化 ...
- 【Nodejs】Nodejsの環境構築
参考URL:http://www.runoob.com/nodejs/nodejs-install-setup.html Windowにインストールする方法を紹介します. ▲ダウンロードURL:htt ...
- 深入JVM之类的加载过程
类的加载—连接—初始化 加载:查找并加载类的字节码文件,从硬盘到内存. 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.la ...
- CF 225C Barcode(DP)
传送门:点我 You've got an n × m pixel picture. Each pixel can be white or black. Your task is to change t ...