面向切面编程详解:Spring AOP详细分析

AOP

  • AOP: Aspect-oriented programming. 面向切面的程序设计
    • 将横切关注点进一步分离,以提高代码的模块化程度
    • 在现有的项目代码的基础上增加额外的通知Advice机制,能够对声明为切点Pointcut的逻辑功能代码块进行统一的管理与装饰
      • 横切关注点: 在项目的多个模块中都有出现的逻辑功能代码
    • 面向切面的程序设计可以将与代码核心业务逻辑联系较弱的功能添加到程序中,同时保证业务代码的可读性
  • AOP核心思想:
    • 从核心关注点分离出横切关注点是面向切面程序设计的核心
      • 分离关注点使得解决特定领域问题的代码从业务逻辑中独立出来
      • 业务逻辑中不再含有针对特定领域问题代码的调用
      • 业务逻辑和特定领域问题的关系通过切面来进行封装和维护
  • AOP和OOP的比较:
    • OOP: 面向对象的程序设计
      • OOP引入了封装,继承和多态来建立一个对象层次结构来模拟公共行为的集合.但是OOP无法为分散的对象引入公共行为
      • OOP适用于定义对象自上而下的关系,不适合定义对象从左到右的关系
    • AOP: 面向切面的程序设计
      • 使用横切的技术,分解封装对象的内部,将影响多个类的公共行为封装到一个可重用的模块称作切面
      • AOP通过横切的关系将与业务无关,但是被业务模块共同调用的逻辑和责任封装起来,减少项目中的重复代码,降低模块之间的耦合度,提升项目的操作性和维护性
  • AOP中的基本概念:
    • 切面: AspectJ
      • 模块化的横切关注点.也就是横向分散在多个功能模块中的特定逻辑功能
    • 连接点: Join point
      • 在项目执行过程中能够在项目中插入切面功能的项目中的某一个点
      • Spring AOPJoinpoint指代的是所有方法的执行点
      • 这个点可以是项目中某个方法调用前,调用后,方法抛出异常后等等
      • 切面利用这些连接点切入到正常的项目流程中,添加某些行为
        • AOP中的Joinpoint可以有多种类型:
          • 构造方法调用
          • 字段的设置和获取
          • 方法的调用
          • 方法的执行
          • 异常处理的执行
          • 类的初始化
          • 注意: Spring中只支持执行方法类型的joinpoint
    • 通知: Advice
      • AOP框架在特定的连接点处执行的动作
      • Spring AOP中提供5种类型的通知Advice:
        • 前置通知: Before. 在目标方法调用之前执行通知功能
        • 后置通知: After. 在目标方法调用完成之后执行通知功能.无论目标方法是否发生异常,后置通知都会执行
        • 后置返回通知: After-returning. 在目标方法返回值之后执行通知功能
        • 后置异常通知: After-throwing. 在目标方法抛出异常之后执行通知功能
        • 环绕通知: Around. 在目标方法调用之前和调用之后执行通知功能
    • 切点: Pointcut
      • 执行通知的一系列连接点的集合
      • Pointcut是一个描述信息,用于修饰Joinpoint, 通过Pointcut,AOP就可以确定哪些Joinpoint可以编织进入Advice
      • AOP通过切点定位到特定的连接点
      • 一个切点匹配多个连接点
    • 引入: Introduction
      • 添加方法或者字段到被通知的类
      • Spring支持引入接口到任何被通知的对象中
      • Spring中使用Introduction, 可以通过DelegatingIntroductionInterceptor来实现通知,通过DefaultIntroductionAdvisor来配置Advice和代理类要实现的接口
    • 目标对象: Target Object
      • 包含连接点的对象.也就是被通知或者被代理的对象
    • AOP代理: AOP Proxy
      • AOP框架创建的对象,包括通知
      • Spring中的AOP代理包括JDK动态代理和CGLIB代理
    • 织入: Weaving
      • 织入描述的是将切面应用到目标对象来创建新的代理对象的过程
        • Spring AOP使用了动态代理技术,在项目运行时织入切面
        • Spring AOP支持使用两种方式JDK动态代理和CGLIB代理生成代理对象.默认策略是如果目标类为接口,则使用JDK动态代理,如果目标类是一个类对象则使用CGLIB代理
  • AOP实现的两种方式:
    • 动态代理方式: 利用拦截方法,对拦截方法进行装饰,取代原有方法的执行
    • 静态织入方式: 引入特定的语法创建切面,使得编译器在编译期间织入切面的代码
  • AOP使用的四种方式:
    • 基于代理模式的AOP使用
    • @AspectJ注解驱动的切面
    • POJO切面,通过 <aop:config /> 配置切面
    • 注入式AspectJ切面,通过 <aop:aspectj-autoproxy /> 配置切面
  • Spring AOP的使用方法有以下三个步骤:
    • 定义增强方法,并在方法里使用AspectJ的注解标注Spring在何处调用方法
    • 在横切方法上使用注解 @Component@Aspect
    • @Configuration配置类上使用注解 @EnableAspectJAutoProxy
  • Spring AOP中XML配置使用示例
  • SpringBoot AOP中注解式使用示例
  • AOP中的切入点表达式: 切入点表达式用来指定切入点的目标
    execution([modifier-pattern]? [return-type-pattern] [declaring-type-pattern]? [name-pattern]([param-pattern])[throws-pattern]?)
    
    • modifier-pattern: 修饰符匹配
    • return-type-pattern: 返回值匹配
    • declaring-type-pattern: 类路径匹配
    • name-pattern: 方法名匹配
    • param-pattern: 参数匹配
    • throws-pattern: 异常类型匹配
    • ? : 表示该匹配项是可选项
      • 示例:
        • 匹配所有方法:
        execution(* *(..))
        
        • 匹配com.oxford.service包下面的所有公共方法:
        execution(public * com.oxford.service.*(..))
        
        • 匹配com.oxford.service包以及子包下面的所有方法:
        execution(* com.oxford.service..*.*(..))
        
    • 使用 @Pointcut定义切点时,可以使用 &&, ||! 逻辑运算符

面向切面的基础

  • 面向切面程序设计的核心概念就是从核心关注点中分离出横切关注点:
    • 分离关注点使得解决特定领域问题的逻辑功能代码从业务逻辑代码中独立出来
    • 业务逻辑代码中不再含有对特定领域问题的逻辑功能代码的调用
    • 业务逻辑代码同对特定领域问题的逻辑功能代码的关系通过切面来进行封装和维护
  • 关注点: Concern
    • 对软件工程有意义的,小的,可管理的,可描述的软件组成部分
    • 一个关注点通常只和一个特定概念或者目标相关联
  • 主关注点: Core Concern
    • 一个软件中的最主要的关注点
  • 关注点分离: Separation of concerns, SOC
    • 标识,封装和操作关注点的能力
  • 方法: Method
    • 用来描述,设计和实现一个给定关注点的软件构造单位
  • 横切: Crosscut
    • 如果实现两个关注点方法存在交集,那么这两个关注点相互横切
  • 支配性分解: Dominant decomposition
    • 将软件分解成模块的主要方式
      • 传统的程序设计语言以一种线性的文本来描述软件,只采用一种方式,比如类来将软件分解成模块
      • 这样使得某些关注点比较好捕捉,容易进一步组合,扩展
      • 但是仍然会存在一些关注点没有被捕捉,弥撒在整个软件内部
    • 支配性分解通常是按照主关注点进行模块分解的
  • 横切关注点: Crosscuting concerns
    • 在传统的程序设计语言中,除了主关注点可以被支配性分解的方式捕捉外,仍然有许多没有被支配性分解方式捕捉到的关注点
    • 这些关注点弥散在整个软件内部,这些关注点同主关注点是横切的
  • 切面: Aspect
    • 支配性分解的基础上提供的一种辅助的模块化机制
    • 切面的模块化机制可以捕捉横切关注点

AOP原理剖析

在这里插入图片描述
  • 后置处理器根据Bean是否配置Advisor判断是否需要进行动态代理

  • 如果需要进行动态代理,那么就构造创建ProxyFactory对象

  • 通过ProxyFactory对象的父类中的getAopProxyFactory() 方法获取AopProxyFactory对象,默认获取的是DefaultAopProxyFactory

  • 通过AopProxyFactory工厂createAopProxy() 方法创建实际的代理对象

  • ProxyBeanFactory:

在这里插入图片描述
  • Spring使用工厂模式创建每一个Proxy. 每一个Class类型,都会有一个相对应的ProxyFactoryBean
    • 对于生成Proxy的工厂而言,只需要知道对应的Advice信息即可
    • Advice信息维护在Advised,Advised可以根据特定的类名和方法名返回对应的AdviceChain, 来表示需要执行的Advice
在这里插入图片描述
  • JDK动态代理:
    • JDK动态代理是面向接口的JdkDynamicAopProxy生成代理对象
      • 溯源到JDK动态代理的字节码文件.在反编译的代码文件中可以发现代理类已经是继承了Proxy类,因为Java是单继承多实现的,所以不能再继承其余的类,但是代理类与目标类之间必须建立一种关系来保证代理对象可以被引用到,这样就只能实现接口
      • 目标类实现了至少一个接口时,那么代理类就可以通过实现与目标类相同的接口,使用接口类型的变量接收代理类的实例
    • JdkDynamicAopProxy类实现了AopProxy, 返回Proxy, 并且自身也实现了InvocationHandler
    • 也就是说,当我们使用proxy时,对proxy对象调用的方法,都会转到这个类的invoke() 方法中
  • Cglib代理:
    • 基于Cglib子类继承方式CglibAopProxy生成代理对象
Spring AOP代理选择 代理描述 实现机制 优点
JDK动态代理 1. 通过反射接受被代理的类,并且要求被代理的类必须实现一个接口2. JDK动态代理的核心是InvocationHandler接口和Proxy类 通过Java的内部反射机制实现 反射机制在生成类的过程中非常高效
CGLIB代理 1. 通过继承的方式动态生成目标类的代理2. 通过修改字节码的方式来实现代理,可以在运行时动态的生成某个类的子类3. 如果某个类使用final修饰,那么无法使用CGLIB做动态代理4. CGLIB代理的核心是Enhancer类 使用ASM框架实现. ASM框架是一种可以操作字节码的框架 ASM在类生成之后的执行过程中非常高效
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,527评论 5 470
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,314评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,535评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,006评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,961评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,220评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,664评论 3 392
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,351评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,481评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,397评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,443评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,123评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,713评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,801评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,010评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,494评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,075评论 2 341