切面是如何织入到目标对象中的???这大概是每个人在学习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. 使用eclipse 开发lisp

    https://www.ibm.com/developerworks/cn/opensource/os-eclipse-lispcusp/ eclipse有一个插件,可以支持lisp的开发,叫cusp ...

  2. 点击一个元素,触发另一个元素的click事件

  3. 如何在 Ubuntu 14.04 上安装 Elasticsearch,Logstash 和 Kibana

    介绍 在本教程中,我们将去的 Elasticsearch 麋鹿堆栈安装 Ubuntu 14.04 — — 那就是,Elasticsearch 5.2.x,Logstash 2.2.x 和 Kibana ...

  4. Hibernate(二)持久化对象的状态

    简介 以前学习Hibernate的笔记,整理一下便发出来了,防止弄丢.有错误的话麻烦各位留言评论,感激不尽. 持久化类 Hibernate完成了从面向对象模型表示的对象至关系模型表示的数据结构的映射, ...

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

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

  6. 【学习笔记】--- 老男孩学Python,day8 知识点补充 join,列表不能循环删除,深浅copy

    1. 补充基础数据类型的相关知识点 1. str. join() 把列表变成字符串 2. 列表不能再循环的时候删除. 因为索引会跟着改变 3. 字典也不能直接循环删除. 把要删除的内容记录在列表中. ...

  7. css-图文案例

    效果如下: 附上代码: <html> <head> <title>World</title> <style type="text/css ...

  8. [转]c# winform tcp connect timeout 连接超时设置

    转自:https://www.cnblogs.com/jhlong/p/5622336.html 简单的c# TCP通讯(TcpListener) C# 的TCP Socket (同步方式) C# 的 ...

  9. JS 时间转化为几分钟前 几小时前 几天前

    背景:最近公司要做动态列表,类似于微信朋友圈.动态创建时间就需要显示为 刚刚.几分钟前.几小时前.几天前.2018-05-15,这样的形式. 代码如下 var minute = 1000 * 60; ...

  10. HTML meta标签总结,HTML5 head meta属性整理

    原文链接:http://caibaojian.com/mobile-meta.html <!DOCTYPE html> <!-- 使用 HTML5 doctype,不区分大小写 -- ...