AOP-切面是如何织入到目标对象中的
切面是如何织入到目标对象中的???这大概是每个人在学习AOP的过程中都会产生的疑问吧。
当我们在调用目标方法时候,也就是通过代理对象调用目标方法的时候,比如:JdkDynamicAopProxy会通过连接点(ReflectiveMethodInvocation)来调用拦截器链中的拦截器(也就是调用通知方法)。所以JdkDynamicAopProxy对象首先要获取的拦截器链条,然后才将拦截器链条交给连接点来调用拦截器和目标方法吧。也就是在获取拦截器链条的过程中有一句代码,这行代码再DefaultAdvisorChainFactory的getInterceptorsAndDynamicInterceptionAdvice(..)方法中:
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
我只贴这一句,建议先看下源码。这一句代码前半部分 config.isPreFiltered() 的意思是:config(AdvisedSupport)对象中的Advisor(每个Advisor对象持有一个通知)是否已经经过筛选并与目标对象相匹配。如果已经提前过滤好了(或者说已经提前匹配好了),那就返回true.那if判断就为 true 了。如果说config对象中的Advisor还没有过滤(匹配)过,那么就调用上面的这行代码的后半部分来匹配。
但是我在debug源码的时候发现都是已经提前匹配好了的。也就是说切面在调用目标对象之前已经织入目标对象了。那它是怎么的织入的呢??它时什么时候织入的呢??文章开头的疑问也就是在这个时候产生的。现在我来回答这个问题:切面是在目标对象被实例化的是时候织入目标对象的,更准确的说,切面是在目标对象的bean在完成初始实例化之后bean工厂调用bean的后处理器将切面织入到目标对象中的。就像是一辆汽车生产出来之后已经可以使用了,能正常行驶了。但是最后阶段我还要给它装上仪表,安全气囊,甚至是行车记录仪等等。
既然既然上面所说的config对象就是AdvisedSupport类的实例那就是看看config.isPreFiltered()这句源码

debug截图

看看最关键的代码,在AbstractAutoProxyCreator中的createProxy(..)中也就是上图标出的关键代码。
源码如下:
/**
* Create an AOP proxy for the given bean.
* @param beanClass the class of the bean
* @param beanName the name of the bean
* @param specificInterceptors the set of interceptors that is
* specific to this bean (may be empty, but not null)
* @param targetSource the TargetSource for the proxy,
* already pre-configured to access the bean
* @return the AOP proxy for the bean
* @see #buildAdvisors
*/
protected Object createProxy(
Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) { if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
//ProxyFactory是AdvisedSupport的一个子类。现在创建的也就是上面所说的config对象。这个config对象将会存储与目标对象相匹配的advisor,这就是所谓的织入。
//等到调用目标对象的时候在将advisor取出来包装(转换)成拦截器。最后组成拦截器链。
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this); if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
//这里是给定的拦截器包装成advisor。这个specificInterceptors是作为这个方法的参数传进来的。也就是说在这之前就已经将与目标对象相匹配的拦截器构建好了。
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
for (Advisor advisor : advisors) {
//这里就是织入,将与目标对象相匹配的advisor存储到config中,也就是一个AdvisedSupport对象中。
proxyFactory.addAdvisor(advisor);
} proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory); proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);//调用我上面打断点的那个方法。
} return proxyFactory.getProxy(getProxyClassLoader());
}
现在看看程序是如何获取与目标对象匹配的advisor的。也就是上述代码中的specificInterceptors 是如何构建的。
这过程实在是太复杂,看了下源码,感觉不可能把源码贴上来结合着讲。说下思路吧,目前只看了一遍源码,可能会有出入的地方:因为advisor是在bean工厂初始化完成的时候就完成了实例化的。所以现在它现将所有用于自动代理的advisor获取,即不管是不是与目标对象匹配,我先拿过来。然后在进行筛选与目标匹配的advisor。筛选当然是遍历每一个advisor。在判断一个advisor是否与目标对象匹配的时候,因为每个advisor都会持有一个切点和一个通知的引用。所以先从advisor中获取切点对象。然后又通过切点获取一个ClassFilter对象(每个切点都持有一个ClassFilter对象),也就是说这个ClassFilter间接属于advisor。ClassFilter,顾名思义,就是拿来过滤的。它有一个的matches(Class<?> clazz)方法。这个方法将目标对象类型作为参数,传进去匹配。如果相匹配返回true。而这仅仅是类型符合了。但是这个目标类对象中并不是所有的方法后符合啊。
所以还要判断目标方法是否符合。所以还需要一个MethodMatcher对象(注:Methodmatcher和ClassFilter都是接口)。MethodMatcher对象也有一个方法叫maches(..)。将目标对象的所有目标方法(Method对象)一个个比较,如果有符合的就返回true。说明advisor和目标对象相符合。
AOP-切面是如何织入到目标对象中的的更多相关文章
- Spring AOP 之编译期织入、装载期织入、运行时织入(转)
https://blog.csdn.net/wenbingoon/article/details/22888619 一 前言 AOP 实现的关键就在于 AOP 框架自动创建的 AOP 代理,AOP ...
- 框架源码系列三:手写Spring AOP(AOP分析、AOP概念学习、切面实现、织入实现)
一.AOP分析 问题1:AOP是什么? Aspect Oriented Programming 面向切面编程,在不改变类的代码的情况下,对类方法进行功能增强. 问题2:我们需要做什么? 在我们的框架中 ...
- Spring配置AOP实现定义切入点和织入增强
XML里的id=””记得全小写 经过AOP的配置后,可以切入日志功能.访问切入.事务管理.性能监测等功能. 首先实现这个织入增强需要的jar包,除了常用的 com.springsource.org.a ...
- AOP的核心:代理与织入
分为两步: 1.动态生成代理类: 2.织入: 2.6 织入(Weaving) 织入是将增强添加到目标的具体连接点上的过程 . AOP 织入方式: 方式 实现 应用编译期织入 特殊的 Java 编译器. ...
- spring Aop切面中的@Before @Around等执行顺序与请求参数统一解码
1.背景 在实际开发中,我可能会对请求接口做统一日志输出,或者统一参数解析,验签,统一响应加密等,通常会用到aop,实际案例如下 2.代码 package com.qianxingniwo.log; ...
- 关于Aop切面中的@Before @Around等操作顺序的说明
[转]http://www.cnblogs.com/softidea/p/6123307.html 话不多说,直接上代码: package com.cdms.aop.aspectImpl; impor ...
- AOP切面用于系统日志
import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.*; import org.springframework. ...
- 一文带你搞定AOP切面
摘要:AOP在spring中又叫"面向切面编程",是对传统我们面向对象编程的一个补充,主要操作对象就是"切面",可以简单的理解它是贯穿于方法之中,在方法执行前. ...
- Java AOP (1) compile time weaving 【Java 切面编程 (1) 编译期织入】
According to wikipedia aspect-oriented programming (AOP) is a programming paradigm that aims to inc ...
随机推荐
- PHP数组基本的操作方法
1.数组操作的基本函数 数组的键和值: array_values($arr);获得数组的值 array_keys($arr);获得数组的键名 array_flip($arr);数组中的值与键名互换(如 ...
- mui 百度语音识别转换文字
前言 用mui混合开发的APP,现有一个功能需求就是语音转换成文字,并把语音进行保存.对此考虑两种选择讯飞和百度.最终选择了百度语音. 百度语音 通过官方文档我们大致可以确定如果想要实现语音识别,要做 ...
- Angular CLI 安装和使用以及安装失败的解决方法
背景介绍 关于Angular版本,Angular官方已经统一命名Angular 1.x同一为Angular JS:Angular 2.x及以上统称Angular: CLI是Command Line I ...
- Python中类的属性的访问控制
因为自己是做.NET的,之前有学习过Python,喜欢这门语言的很多特性,最近又不时看了一会儿,将自己的感受分享给大家,其中也难免会用C#的角度看Python的语法,主要还是讲下Python中类中对属 ...
- Spring Boot + MyBatis + Druid + Redis + Thymeleaf 整合小结
Spring Boot + MyBatis + Druid + Redis + Thymeleaf 整合小结 这两天闲着没事想利用**Spring Boot**加上阿里的开源数据连接池**Druid* ...
- 在SecureCRT中给linux上传和下载文件
下载:sz中的s意为send(发送),告诉客户端,我(服务器)要发送文件 send to cilent,就等同于客户端在下载. 上传:rz中的r意为received(接收),告诉客户端,我(服务器)要 ...
- 山东第四届省赛: Boring Counting 线段树
http://acm.sdibt.edu.cn/JudgeOnline/problem.php?id=3237 Problem H:Boring Counting Time Limit: 3 Sec ...
- xamarin.Android 选择本地图片、拍摄图片、剪裁图片
[Activity(Theme = "@style/MyStyleBottom")] public class SelectPicPopupWindow : Activity, I ...
- python学习之老男孩python全栈第九期_第二周学习总结
迭代器 双下方法:很少直接调用的方法,一般情况下,是通过其他语法触发的 1. 可迭代的 --> 可迭代协议:含有__iter__的方法( '__iter__' in dir(数据) ) 可迭代的 ...
- ArcGIS Server命令行工具学习笔记
备份命令 backup.py 参数: -u 管理员账号 -p 密码 -s 站点URL -f 备份文件的存储目录路径 -h 显示帮助 还原命令 restore.py 参数: -u 管理员账号 -p 密码 ...