切面是如何织入到目标对象中的???这大概是每个人在学习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. vb.net的String类型和Bytes转换(C#也适用)

    1.Bytes---->StringSystem.Text.Encoding.Unicode.GetString(bytes, 0, bytes.Length) 2.String----> ...

  2. 简单的自定义Session

    有关Session.Cookie机制建议参考文章:CookieSession机制详解,写的很详细,不再赘述 本篇文章通过一个简单的案例揭秘Session机制以及和Cookie的区别和联系: 服务器端代 ...

  3. Android基础知识你知道多少?

    https://github.com/zhantong/interview/blob/master/Android/Android.md 四大组件是什么? 四大组件的启动方式? Activity生命周 ...

  4. FastJson的忽略字段和格式日期用法

     1.指定序列化顺序 缺省fastjson序列化一个java bean,是根据fieldName的字母序进行序列化的,你可以通过ordinal指定字段的顺序.这个特性需要1.1.42以上版本. pub ...

  5. Vue双向绑定原理详解

    前言:Vue最核心的功能之一就是响应式的数据绑定模式,即view与model任意一方改变都会同步到另一方,而不需要手动进行DOM操作,本文主要探究此功能背后的原理. 思路分析 以下是一个最简单的双向绑 ...

  6. 关于HSTS的总结

    访问http网站,和服务器交互的步骤浏览器向服务器发起一次HTTP请求服务器返回一个重定向地址浏览器在发送一次HTTPS请求,得到最终内容 上面浏览器发送http请求后容易被拦截,使用HSTS后可以避 ...

  7. opencv3.2.0形态学滤波之形态学梯度、顶帽、黑帽

    /*一.形态学梯度 (1)含义:是膨胀图和腐蚀图之差 (2)数学表达式:dst=morph-grad(src,element) =dilate(src,element) - erode(src,ele ...

  8. Debian 8 升级到 9 Debian 9 How to upgrade Debian 8 Jessie to Debian 9 Stretch

    How to upgrade Debian 8 Jessie to Debian 9 Stretch Contents 1. Objective 2. What's New 3. Preparatio ...

  9. 专访阿里资深研发工程师窦贤明:PG与商业数据库差距并不明显

    窦贤明认为, 支持类型.功能和语法丰富,性能优良   9月24日,窦贤明将参加在北京举办的线下活动,并做主题为<Greenplum分片案例分析>的分享.值此,他分享了PG.工作上的一些经历 ...

  10. HTTP请求封装:Ajax与RESTful API

    一.HTTP请求 HTTP即超文本传输协议,用以进行HTML 文件. 图片文件. 查询结果等的网络传输. 一个完整的HTTP请求包括:请求行.请求头.空行和请求数据(请求数据可以为空) HTTP1.1 ...