Spring学习笔记(五)AOP

AOP

AOP: (Aspect Oriented Programming)面向切面编程

作用:在不惊动原始设计的基础上为其增强功能

核心概念

image-20230307171741341
image-20230307172019772

切面补充:在AOP中,切面(Aspect)是一种模块化的、可重用的代码单元,它用于实现横切关注点的功能。具体地,切面可以定义一组通知(Advice)和切入点(Pointcut),用于拦截和处理目标对象的方法调用。

使用步骤

1.导入坐标(pom.xml)

 <dependency>
     <groupId>org.aspectj</groupId>
     <artifactId>aspectjweaver</artifactId>
     <version>1.9.19</version>
 </dependency>

aop的包其实也需要导入,但是spring-context的包导入之后,aop就级联导入了,所以只需要再导入aspectjweaver

image-20230307214452602

2.准备好连接点方法(原始操作,dao接口与实现类)

3.建立共性方法(通知和通知类)

4.定义切入点

 //定义切入点
 @Pointcut("execution(void com.yuan.dao.BookDao.update())")
 private void pt(){}
 //上述切入点表达式引用实现类的方法也可以,效果一样,即:
 //@Pointcut("execution(void com.yuan.dao.impl.BookDaoImpl.update())")

5.绑定切入点和通知方法(切面)

 @Component
 @Aspect
 public class MyAdvice
 {
     //定义切入点
     @Pointcut("execution(void com.yuan.dao.BookDao.update())")
     private void pt(){}
 ​
     //绑定切入点和通知方法(切面)
     @Before("pt()")
     public void method(){
         System.out.println(System.currentTimeMillis());
    }
 }

其中@Component注解指定该类为一个可供spring管理的bean,@Aspect告诉spring这个类不是一个普通的bean,而是一个切面aop.

6.spring配置文件中添加注解

 @Configuration
 @ComponentScan("com.yuan")
 @EnableAspectJAutoProxy
 public class SpringConfig {
 }

@EnableAspectJAutoProxy注解告诉spring项目中有用注解开发的aop,即该注解启动了通知类的注解@Aspect.

AOP工作流程

核心:代理模式

1.spring容器启动

2.读取所有切面配置中的切入点。即只读取绑定了通知类的切入点,没有绑定的切入点不管它(因为没有绑定的话和没有建立切入点是一样的呀)

3.初始化bean,判定bean对应的类的方法是否匹配到切入点

  • 匹配失败,创建对象
  • 匹配成功,创建原始对象(目标对象)的代理对象

4.获取bean执行方法

  • 获取bean,调用方法并执行
  • 获取的bean是代理对象时,根据代理对象的运行模式运行原始方法和增强的内容,完成操作

读取aop配置要在初始化bean之前,因为spring要判断是否需要创建代理对象。

切入点表达式

注意:切入点是指要增强的方法,切入点表达式是要增强的方法的描述方式。

  • 动作关键字(访问修饰符 返回值 包名.类/接口名.方法名(参数) 异常名)
  • 访问修饰符和异常名可以省略
  • image-20230308155429638
  • 注意:
    • 描述切入点通常描述接口,不描述实现类(降低耦合)
    • 访问控制修饰符针对接口开发均采用public描述(可省略)
    • 返回值类型 对于增删改类型使用精准类型加速匹配,对于查询类型使用*通配快速描述
    • 包名尽量不用..匹配(效率低),常用*或精准匹配
    • 接口名/类名书写名称与模块相关的采用*匹配,eg.UserService写成*Service,绑定业务层接口
    • 方法名书写以动词进行精准匹配,名词采用*匹配,eg.getById写为getBy*,selectAll写为selectAll
    • 通常不使用异常

AOP通知类型

 @Component
 @Aspect
 public class MyAdvice
 {
     //定义切入点
     @Pointcut("execution(* com.yuan.*.*.*e(..))")
     private void pt(){}
 ​
     //绑定切入点和通知方法(切面)
     //前置通知
     @Before("pt()")
     public void method(){
         System.out.println(System.currentTimeMillis());
    }
 ​
  //后置通知
     @After("pt()")
     public void after(){
         System.out.println("after");
    }
 ​
     //环绕通知
     @Around("pt()")
     public Object around(ProceedingJoinPoint pjp) throws Throwable {
         System.out.println("before around");
         Object ret = pjp.proceed();
         System.out.println("after around");
         return ret;
    }
 ​
     //返回后通知(了解)
     @AfterReturning("pt()")
     public void afterReturning(){
         System.out.println("after returning");
    }
 ​
     //抛出异常后通知(了解)
     @AfterThrowing("pt()")
     public void afterThrowing(){
         System.out.println("after throwing");
    }
 }
  • 最重要的是@Around注解,标准格式如上述代码,因为某些切入点方法有返回值,所以需要返回Object类型结果
  • 环绕通知需要依赖形参ProceedingJoinPoint才能对原始方法调用
  • 环绕通知无法预知原始方法运行后是否会有异常,故需要抛出异常Throwable

AOP通知获取数据

没什么好说的,用的比较少,了解一下:around用ProceedingJointPoint,其他用JointPointgetArgs()方法。

AOP的应用场景

AOP(面向切面编程)是一种编程范式,它通过将横切关注点(如日志记录、性能统计、安全控制等)从业务逻辑中分离出来,实现了系统的松耦合和高内聚。AOP主要应用于以下场景:

1.日志记录

通过AOP,我们可以在应用程序的不同层次上记录日志,例如方法调用、异常捕获等,以便后续的问题排查和性能优化。

2.缓存管理

AOP可以用来实现缓存管理,例如在方法执行前检查缓存中是否存在相应的数据,如果存在则直接返回缓存数据,否则执行方法并将结果存入缓存。

3.安全控制

AOP可以用来实现安全控制,例如在方法执行前检查用户权限,如果用户没有相应的权限则拒绝访问。

4.事务管理⭐

AOP可以用来实现事务管理,例如在方法执行前开启事务,在方法执行后根据执行结果提交或回滚事务。

5.性能统计

AOP可以用来实现性能统计,例如在方法执行前记录开始时间,在方法执行后记录结束时间,并计算方法执行时间。

总之,AOP可以在不修改原有业务逻辑的情况下,通过横向切割关注点来实现各种横切关注点的功能,从而提高系统的可维护性、可扩展性和可重用性。

chatGPT对应用场景举例:https://webapp.chatgpt4google.com/s/MzEwNjY4

总的来说,其实aop就是把大量重复工作抽离出来,建立通知类,应用于对应的方法场景,降低耦合度。这和直接封装方法,在需要的地方调用的区别在于,后者需要更改原来的代码(添加调用),开关都过于麻烦;并且有些代码和实际业务无关,例如性能统计等,写在aop中更清晰。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注