切面是如何织入到目标对象中的???这大概是每个人在学习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. 导出为shape文件

    private void barButtonItem2_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)//导出为s ...

  2. RegExp正则表达式——更深层次解析

    转自:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/RegExp RegExp 构造 ...

  3. 深复制与浅复制&&strong,copy修饰符总结

    又是一个老生常谈的话题,可是貌似这个问题,好多ios开发工程师并不能理解透彻,所以简单记录分析一下深复制与浅复制的原理以及strong,copy修饰符的原理和使用.   一.深复制与浅复制      ...

  4. DHU 1788 Chinese remainder theorem again 中国剩余定理

    Chinese remainder theorem again Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 ...

  5. 【学习笔记】--- 老男孩学Python,day16-17 初识面向对象,类名称空间,查询顺序,组合

    面向过程 VS 面向对象 面向过程的程序设计的核心是过程(流水线式思维),过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西. 优点是:极大的降低了写程序的复 ...

  6. ArcGIS Server集群布署

    ArcGIS Server集群布署 准备如下的4台机器: 计算机名 IP 布署软件 说明 VMWIN2008ENSS1 192.168.1.111 ArcGIS for Server   VMWIN2 ...

  7. 一起来学习android自定义控件—边缘凹凸的View

    1前言 最近做项目的时候遇到一个卡劵的效果,由于自己觉得用图片来做的话可以会出现适配效果不好,再加上自己自定义view方面的知识比较薄弱,所以想试试用自定义View来实现.但是由于自己知识点薄弱,一开 ...

  8. js原生实现轮播

    前两天同事面试新人,让现场写”轮播的实现”.我一想这玩意貌似我也没写过啊,就在旁边暗搓搓地拖了一张纸也在那写,同事都纳闷了! 这玩意实现方法有很多种,就看喜欢那种,喜欢怎么写而已.我这里是通过对img ...

  9. @Secured()、 @PreAuthorize() 、 @RolesAllowed()

    在Spring security的使用中,为了对方法进行权限控制,通常采用的三个注解,就是@Secured().@PreAuthorize().@RolesAllowed(). 示例,修改用户密码必须 ...

  10. webstorm忽略node_modules目录

    我在使用了cnpm后node_modules之前的层级目录变成了同一级目录,所以目录很多,造成webstorm读取时卡死. 网上大家列了各种方法,在这里我归纳一下! 先给大家看看一些相关链接. 方法1 ...