切面是如何织入到目标对象中的???这大概是每个人在学习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-切面是如何织入到目标对象中的的更多相关文章

  1. Spring AOP 之编译期织入、装载期织入、运行时织入(转)

    https://blog.csdn.net/wenbingoon/article/details/22888619 一   前言 AOP 实现的关键就在于 AOP 框架自动创建的 AOP 代理,AOP ...

  2. 框架源码系列三:手写Spring AOP(AOP分析、AOP概念学习、切面实现、织入实现)

    一.AOP分析 问题1:AOP是什么? Aspect Oriented Programming 面向切面编程,在不改变类的代码的情况下,对类方法进行功能增强. 问题2:我们需要做什么? 在我们的框架中 ...

  3. Spring配置AOP实现定义切入点和织入增强

    XML里的id=””记得全小写 经过AOP的配置后,可以切入日志功能.访问切入.事务管理.性能监测等功能. 首先实现这个织入增强需要的jar包,除了常用的 com.springsource.org.a ...

  4. AOP的核心:代理与织入

    分为两步: 1.动态生成代理类: 2.织入: 2.6 织入(Weaving) 织入是将增强添加到目标的具体连接点上的过程 . AOP 织入方式: 方式 实现 应用编译期织入 特殊的 Java 编译器. ...

  5. spring Aop切面中的@Before @Around等执行顺序与请求参数统一解码

    1.背景 在实际开发中,我可能会对请求接口做统一日志输出,或者统一参数解析,验签,统一响应加密等,通常会用到aop,实际案例如下 2.代码 package com.qianxingniwo.log; ...

  6. 关于Aop切面中的@Before @Around等操作顺序的说明

    [转]http://www.cnblogs.com/softidea/p/6123307.html 话不多说,直接上代码: package com.cdms.aop.aspectImpl; impor ...

  7. AOP切面用于系统日志

    import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.*; import org.springframework. ...

  8. 一文带你搞定AOP切面

    摘要:AOP在spring中又叫"面向切面编程",是对传统我们面向对象编程的一个补充,主要操作对象就是"切面",可以简单的理解它是贯穿于方法之中,在方法执行前. ...

  9. Java AOP (1) compile time weaving 【Java 切面编程 (1) 编译期织入】

    According to wikipedia  aspect-oriented programming (AOP) is a programming paradigm that aims to inc ...

随机推荐

  1. attempt to write a readonly database错误的解决(C#,SQLite)

    今天打包WPF程序,安装后总是打不开,查看监控日志原来是SQLite的问题,报错如图 当向SQLite数据库中存入新纪录时总是显示attempt to write a readonly a datab ...

  2. Java多线程学习之synchronized总结

    0.概述 synchronized是Java提供的内置的锁机制,来实现代对码块的同步访问,称为内置锁(Intrinsic Lock) .内置锁包括两部分:一个是作为锁的对象的引用,另一个是由这个锁保护 ...

  3. 云服务器部署mongodb

    我喜欢用简单的方法 步骤 下载 解压并运行 远程连接测试 下载 到官方下载页获取下载地址,如图 在云服务器上,使用命令curl 你的地址 -o mongodb.tgz ,下载到当前目录,转到下一步. ...

  4. 应用程序框架(一):DDD分层架构:领域实体(基础篇)

    一.什么是实体 由标识来区分的对象称为实体. 实体的定义隐藏了几个信息: 两个实体对象,只要它们的标识属性值相等,哪怕标识属性以外的所有属性值都不相等,这两个对象也认为是同一个实体,这意味着两个对象是 ...

  5. Angular 框架介绍

    库和框架的区别 jQuery:库 库一般都是封装了一些常用的方法 自己手动去调用这些方法,来完成我们的功能code $('#txt').val('我是小明'); $('div').text('xx') ...

  6. [WEB面试题] web前端面试题JavaScript第一弹,个人整理部分面试题汇总

    以下内容仅供参考,成年人不讲对错只讲利弊 1.什么是JavaScript原型链?如何理解 JavaScript中的每个对象都有一个prototype属性,我们称之为原型 原型的值是一个对象有自己的原型 ...

  7. CRM 安装过程 AD+SQL+CRM

    AD: 通过服务器管理器添加域服务,配置域服务器域名为crm5.lab. 注意:使用高级模式安装. 说明:服务器是windows server 2003 那么就选windows server 2003 ...

  8. ifup / ifdown eth0 / eno1 reports unknown interface when it exists!

    li {list-style-type:decimal;}.wiz-editor-body ol.wiz-list-level2 > li {list-style-type:lower-lati ...

  9. 通过代码动态创建IIS站点

    对WebApi进行单元测试时,一般需要一个IIS站点,一般的做法,是通过写一个批处理的bat脚本来实现,其实通过编码,也能实现该功能. 主要有关注三点:应用程序池.Web站点.绑定(协议类型:http ...

  10. 网络 互联网接入方法、Mbit与MB的转换

    ADSL:非对称数字用户环路(绝大多数家庭接入方法,使用电话线).可以提供最高1Mbps的上行速率和最高8Mbps的下行速率.最新的ADSL2+可以提供最高24Mbps的下行速率. 千千兆TB 千兆G ...