Java EE3-我独自整合(第六章:Spring AOP 工作流程与切入点表达式)

AOP 工作流程 (了解)

  1. Spring 容器启动
  2. 读取所有切面配置中的切入点(读取的是全部配置,强调切入点,是因为现在说明的就 是 AOP 相关工作流程)
  3. 初始化 bean,判定 bean 对应的类中的方法是否匹配到任意切入点
    1. 匹配失败,不创建代理对象,仅创建目标对象
    2. 匹配成功,创建原始对象(目标对象)的代理对象
  4. 获取 bean 执行方法
    1. 获取 bean,调用方法并执行,完成操作
    2. 获取的 bean 是代理对象时,根据代理对象的运行模式运行原始方法与增强的内容, 完成操作
  • 目标对象(Target):原始功能去掉共性功能对应的类产生的对象,这种对象是无法直 接完成最终工作的
  • 代理(Proxy):目标对象无法直接完成工作,需要对其进行功能回填,通过原始对象的代理对象实现

切入点表达式

切入点就是要进行增强的方法,切入点表达式就是要进行增强的方法的描述方式

表达式组成

  • 切入点表达式标准格式:
    • 动作关键字(访问修饰符 返回值 包名.类/接口名.方法名(参数表)异常)
      • 动作关键字:描述切入点的行为动作,例如 execution 表示执行到指定切入点
      • 访问修饰符:public,private 等,可以省略
      • 返回值:具体的返回值类型
      • 包名
      • 类/接口名
      • 方法名
      • 参数表,只写类型,不写参数名
      • 异常:方法定义中抛出指定异常,可以省略
        综上所述,一个完整的表达式如下

执行 com.tianshi.service 包中,StudentService 接口中的没有返回值的,命名为 saveStudent,唯一参数类型是 com.tianshi.bean.Student 的方法

java 复制代码
execution( void com.tianshi.service.StudentService.saveStudent(com.tianshi.bean.Student) )

执行 com.tianshi.service.impl 包中,StudentServiceImpl 类中,返回值类型是 java.util.List,命名为 getAllStudents 的无参数方法

java 复制代码
execution( java.util.List com.tianshi.service.impl.StudentServiceImpl.getAllStudents() )

表达式通配符

  • 看到上面的例子,发现编写切入点表达式的时候是非常的麻烦,Spring 可以使用通配符 来描述切入点表达式,从而实现快速描述

通配符 *

  • 代表任意单个独立的任意符号。它可以出现在类名、方法名、返回值或参数列表中 的任意位置,用来匹配任意的字符。但是,当它用于方法参数时,表示任意类型的一个参数
    • 使用场景
  1. 类名或接口名:可以用来匹配任意的类或接口名称的全部或部分字符
java 复制代码
// 可以匹配所有以 Service 结尾的类或接口
execution( void com.tianshi.service.*Service.saveStudent(com.tianshi.bean.Student) )
  1. 方法名:用于匹配方法名中的任意个字符
java 复制代码
// 匹配接口 StudentService 中的任意方法 
execution( void com.tianshi.service.StudentService.*(com.tianshi.bean.Student) ) 
// 匹配接口 StudentService 中所有以 get 开头的方法 
execution( void com.tianshi.service.StudentService.get*(com.tianshi.bean.Student) )
  1. 返回值:用于匹配任意类型返回值的方法
java 复制代码
execution( * com.tianshi.service.StudentService.*(com.tianshi.bean.Student) )
  1. 参数列表:单独使用时,如 (*),表示该方法可以接受任意类型的一个参数;但在实际应用中,通 常与其它通配符结合使用来表示任意数量的参数
java 复制代码
// 匹配接口 StudentService 中的仅有一个任意类型参数的任意方法
execution( * com.tianshi.service.StudentService.*( * ) )

通配符...

  • 连续的两个点,代表任意数量(包括零)的任意符号,可以独立出现,常用于匹配 包名的层级或者方法参数列表
    • 使用场景:
  1. 包名:在匹配包路径时,... 可以用来表示当前包及其所有子包
java 复制代码
// 匹配 com.tianshi 包及其所有子孙包中所有以 Service 结尾的接口或类中,仅有唯一参数 的任意方法 
execution( * com.tianshi..*Service.*(*) )

2.参数列表:在方法签名中,(...) 表示任意数量和类型的参数,这比单个 * 更加灵活,可以匹配无 参数方法、单一参数方法或多个参数的方法

java 复制代码
// 匹配 com.tianshi 包及其所有子孙包中所有以 Service 结尾的接口或类中的任意方法 
execution( * com.tianshi..*Service.*(..) )

表达式书写技巧

  • 所有代码按照标准规范开发,否则以下技巧全部失效
    • 描述切入点通常描述接口,而不描述实现类
    • 访问控制修饰符针对接口开发均采用 public 描述(可省略访问控制修饰符描述
    • 返回值类型对于增删改类使用精准类型加速匹配,对于查询类使用*通配快速描述
    • 包名书写尽量不使用...匹配,效率过低,常用*做单个包描述匹配,或精准匹配。 方法参数表都通过...配置
    • 接口名 /类名书写名称与模块相关的采用*匹配,例如 UserService 书写成*Service, 绑定业务层接口名 接口名规范 : XxxDao XxxService IXxxDao IXxxService 实现类名规范: XxxDaoImpl XxxServiceImpl XxxDao XxxService
    • 法名书写以动词进行精准匹配,名词采用匹配,例如 getById 书写成 getBy ,insertStudent 写成 insert*,selectAll 书写成 selectAll
      • DAO 方法名: insertXxx() updateXxx() deleteXxxx() selectXxx()
      • Service 方法名: addXxx() saveXxx() modifyXxx() dropXxx() removeXxx() getXxx() findXxx()
    • 参数规则较为复杂,根据业务方法灵活调整
    • 通常不使用异常 作为匹配规则,省略异常的配置
相关推荐
小小仙。1 小时前
IT自学第四十天
spring·docker
景庆1972 小时前
vscode启动springBoot项目配置,激活环境
java·开发语言·vscode
小则又沐风a2 小时前
Linux使用指南和基础指令(1)
java·linux·运维
三千星2 小时前
Java开发者转型AI工程化Week 2:从核心能力到生产就绪
java·ai编程
亦暖筑序2 小时前
让 AI 客服真能用的 3 个模块:情绪感知 + 意图识别 + Agent 工具链
java·人工智能·后端
SimonKing2 小时前
别让你的代码裸奔!Spring Boot混淆全攻略(附配置)
java·后端·程序员
m0_634865402 小时前
idea快捷建项目
java·ide·intellij-idea
前端技术2 小时前
[特殊字符]️ Spring AI Alibaba Advisor基础应用
java·人工智能·spring
Fate_I_C2 小时前
实战案例:用 Kotlin 重写一个 Java Android 工具类
android·java·kotlin