spring aop 原理笔记

AOP的核心思想就是“将应用程序中的商业逻辑同对其提供支持的通用服务进行分离。”

实现AOP的技术,主要分为两大类:
一是采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;
二是采用静态织入的方式,引入特定的语法创建“方面”,从而使得编译器可以在编译期间织入有关“方面”的代码。

AOP使用场景
AOP用来封装横切关注点,具体可以在下面的场景中使用:

Authentication 权限
Caching 缓存
Context passing 内容传递
Error handling 错误处理
Lazy loading 懒加载
Debugging  调试
logging, tracing, profiling and monitoring 记录跟踪 优化 校准
Performance optimization 性能优化
Persistence  持久化
Resource pooling 资源池
Synchronization 同步
Transactions 事务

代理方式:
cjlib CGLIB底层封装了ASM,通过对字节码的操作来生成类,具有更高的性能。
jdkproxy 代理 接口方式 InvocationHandler,Proxy,

aop 源码解读笔记
第一阶段:AnnotationAwareAspectJAutoProxyCreator组件(ASPECT自动代理创建器),注册组件
@EnableAspectJAutoProxy//开启aop- spring开启aop注解
public @interface EnableAspectJAutoProxy
boolean proxyTargetClass() default false; --默认false,采用JDK动态代理织入增强(实现接口的方式);如果设为true,则采用CGLIB动态代理织入增强
boolean exposeProxy() default false;--是否可以根据aopContext进行检索
@Import(AspectJAutoProxyRegistrar.class)----导入(注册这个bean)
进入 AspectJAutoProxyRegistrar -》
AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar
它实现了 ImportBeanDefinitionRegistrar(动态导入bean)
要实现的方法
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry);
作用:根据值注册,升级和配置AspectJ自动代理创建程序 会根据前面注解中配置的代理方式来注册这个组件

@Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

//注册一个这个组件, 如果有需要的话....
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

AnnotationAttributes enableAspectJAutoProxy =
AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
//代理方式?
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
//这里根据之前注解进来的参数 要不要放到ExposeProxy?
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}

继续跟进:AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
-》
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
return registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, (Object)null);
}
-》
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}

分析:registerOrEscalateApcAsRequired 注册或者升级---AnnotationAwareAspectJAutoProxyCreator.class
(这就是第一阶段我们要注册的aop组件)

tip: 这里
BeanDefinitionRegistry 是一个接口, 实现了AliasRegistry接口, 定义了一些对 bean的常用操作
1: 以Map<String, BeanDefinition>的形式注册bean
2:根据beanName 删除和获取 beanDefiniation ,得到持有的beanDefiniation的数目,根据beanName 判断是否包含 beanDefiniation等

接上面 registerOrEscalateApcAsRequired 流程
通过registry判断org.springframework.aop.config.internalAutoProxyCreator 在容器中有没有
第一次没有存在 则 去创建 (org.springframework.aop.config.internalAutoProxyCreator 内部定义的组件名)
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add("order", -2147483648);
beanDefinition.setRole(2);
registry.registerBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator", beanDefinition);
return beanDefinition;

AnnotationAwareAspectJAutoProxyCreator神奇的组件分析:
类关系图如下,继承关系:
AnnotationAwareAspectJAutoProxyCreator:

  • AnnotationAwareAspectJAutoProxyCreator
  • ->AspectJAwareAdvisorAutoProxyCreator
  •    ->AbstractAdvisorAutoProxyCreator
    
  •       ->AbstractAutoProxyCreator
    
  •         implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware
    
  •                  关注后置处理器(在bean初始化完成前后做事情)、自动装配BeanFactory
    

SmartInstantiationAwareBeanPostProcessor: bean的后置处理器
BeanFactoryAware 能把beanFacotry bean工厂传进来
通过分析以上的bean继承关系我们发现, 具有BeanPostProcessor特点, 也有Aware接口的特点, 实现了BeanFactoryAware 接口

其实是一个spring组件,会有后置处理器在工作 并且拿到了beanFacotry bean

那我们来分析做为beanPostProcessor后置处理器做了哪些工作, 做为BeanFactoryAware又做了哪些工作

第二阶段:AnnotationAwareAspectJAutoProxyCreator 的工作原理
实现了beanPostProcessor 所以容器会怼他创建成一个后置处理器类 放入容器
定制了一个 特置的后置处理器
其他bean在创建时 将(增强器 切面类)放入advisedBeans (map)中
给增强器排序
需要增强的bean创建代理类过程
1)、获取当前bean的所有增强器(通知方法) Object[] specificInterceptors
1、找到候选的所有的增强器(找哪些通知方法是需要切入当前bean方法的)
2、获取到能在bean使用的增强器。
3、给增强器排序
2)、保存当前bean在advisedBeans中;
3)、如果当前bean需要增强,创建当前bean的代理对象;
1)、获取所有增强器(通知方法)
2)、保存到proxyFactory
3)、创建代理对象:Spring自动决定
JdkDynamicAopProxy(config);jdk动态代理;
ObjenesisCglibAopProxy(config);cglib的动态代理;
4)、给容器中返回当前组件使用cglib增强了的代理对象;
5)、以后容器中获取到的就是这个组件的代理对象,执行目标方法的时候,代理对象就会执行通知方法的流程;

保存需要代理对象和增强器

第三阶段:目标执行
容器中保存了组件的代理对象(cglib增强后的对象),这个对象里面保存了详细信息(比如增强器,目标对象,xxx);
1)、CglibAopProxy.intercept();拦截目标方法的执行
2)、根据ProxyFactory对象获取将要执行的目标方法拦截器链;
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
1)、List<Object> interceptorList保存所有拦截器 5
一个默认的ExposeInvocationInterceptor 和 4个增强器;
2)、遍历所有的增强器,将其转为Interceptor;
registry.getInterceptors(advisor);
3)、将增强器转为List<MethodInterceptor>;
如果是MethodInterceptor,直接加入到集合中
如果不是,使用AdvisorAdapter将增强器转为MethodInterceptor;
转换完成返回MethodInterceptor数组;

   3)、如果没有拦截器链,直接执行目标方法;
       拦截器链(每一个通知方法又被包装为方法拦截器,利用MethodInterceptor机制)
   4)、如果有拦截器链,把需要执行的目标对象,目标方法,
       拦截器链等信息传入创建一个 CglibMethodInvocation 对象,
       并调用 Object retVal =  mi.proceed();
   5)、拦截器链的触发过程;
       1)、如果没有拦截器执行执行目标方法,或者拦截器的索引和拦截器数组-1大小一样(指定到了最后一个拦截器)执行目标方法;
       2)、链式获取每一个拦截器,拦截器执行invoke方法,每一个拦截器等待下一个拦截器执行完成返回以后再来执行;
          拦截器链的机制,保证通知方法与目标方法的执行顺序;
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,108评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,699评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,812评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,236评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,583评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,739评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,957评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,704评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,447评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,643评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,133评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,486评论 3 256
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,151评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,108评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,889评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,782评论 2 277
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,681评论 2 272

推荐阅读更多精彩内容

  • 前言 说是Java web,Spring已经成为了事实标准,Spring原理的深入学习,无论是在工作中,还是在面试...
    老呼阅读 16,679评论 2 87
  • IOC和DI是什么? Spring IOC 的理解,其初始化过程? BeanFactory 和 FactoryBe...
    justlpf阅读 3,377评论 1 21
  • 1.Spring整体架构 1)核心容器(Core Container) Core模块,主要包含了Spring框架基...
    Sponge1128阅读 984评论 0 1
  • Spring容器高层视图 Spring 启动时读取应用程序提供的Bean配置信息,并在Spring容器中生成一份相...
    Theriseof阅读 2,737评论 1 24
  • 本来是准备看一看Spring源码的。然后在知乎上看到来一个帖子,说有一群**自己连Spring官方文档都没有完全读...
    此鱼不得水阅读 6,903评论 4 21