Spring AOP

AOP思想

AOP指的是面向切面编程,跟OOP面向对象编程一样是一种思想。用一句话概括就是:在面对某一类问题时,主动进行集中处理。

例如在博客系统中,在添加博客,删除博客等场景需要验证你的身份信息,是否已经登入。以往的做法是把验证是否登入功能的代码进行封装,然后在这些板块调用它。但是这就把代码嵌入到这些板块中,耦合度高。如果未来验证是否登入功能的代码进行修改,需要传递参数变了,那么整个项目调用它的板块也要进行修改,维护成本高。而AOP就可以很好的解决这个问题,把验证用户是否登入集中处理,在添加博客,删除博客时会主动帮你处理这个问题,这就让这些板块都只完成自己的要实现的功能,耦合度就降低了。

AOP的组成

切面

通俗理解切面就是程序中一个处理某方面具体问题的一个类,类中包含很多方法,这些方法就是切点和通知

切点

配置主动拦截规则

在博客系统中,添加博客,删除博客等功能中需要验证是否用户登入,而登入功能却不需要,判断一个需不需要就是通过你配置的拦截规则来判断,如果需要就主动帮你处理。

通知

经过拦截规则的判定,如果被拦截下来,后续要实现哪些具体业务代码。

  1. 前置通知:在执行目标方法之前执行的方法
  2. 后置通知:在执行目标方法之后执行的方法
  3. 异常通知:在执行目标方法出现异常时,执行的通知
  4. 返回通知:目标方法执行了返回数据(return)时,执行的通知
  5. 环绕通知:在目标方法执行的周期内(执行之前,执行中,执行后)都可以执行的方法叫做环绕通知
连接点

可能触发AOP拦截规则的所有点(所有请求)

Spring AOP的实现

添加Spring AOP框架支持
xml 复制代码
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-aop -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-aop</artifactId>
			<version>2.7.9</version>
		</dependency>
定义切面和切点
java 复制代码
@Aspect //告诉框架我是一个切面类
@Component //随着框架的启动而启动
public class UserAop {
}
java 复制代码
public class UserAop {
    /*
    定义切点,配置主动拦截规则
		execution()切点函数,用来匹配具体哪个方法
     */
    @Pointcut("execution(* com.example.demo.controller.UserController.*(..))")
    public void pointcut() {
    }
}
拦截规则的配置

execution(<修饰符><返回类型><包.类.方法(参数)><异常>)

  1. 修饰符,一般省略
  2. 返回值,不能省略
    1. void 返回没有值
    2. String 返回字符串
      • 任意
    1. com.example.demo.*.service demo包下任意一个包(该包的下一层是service)
    2. com.example.demo... demo包下的所有包(含自己)
    3. com.example.demo.*.service... demo包下任意包,但再下一层是service, service目录任意包
    1. *Controller 以Controller结尾
    2. User* 以User开头
      • 任意
  3. 方法名,不能省略
    1. add* 以add开头
    2. *xxx 以xxx结尾
      • 任意
  4. 参数
    1. () 无参
    2. (int) 一个整形
    3. (...) 参数任意
  5. +通配符,必须放在类后面,表示继承该类的所有子类包括自己
定义通知
java 复制代码
public class UserAop {
    /*
    定义切点,配置主动拦截规则
     */
    @Pointcut("execution(* com.example.demo.controller.UserController.*(..))")
    public void pointcut() {
    }
    /*
    前置通知
     */
    @Before("pointcut()")
    public void beforeAdvice() {
        System.out.println("执行了前置通知");
    }
    /*
    后置通知
     */
    @After("pointcut()")
    public void afterAdvice() {
        System.out.println("执行了后置通知");
    }

    /**
     * 环绕通知
     * @param ProceedingJoinPoint 规定写法
     * @return 返回Object给框架
     */
    @Around("pointcut()")
    public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("进入环绕通知");
        Object obj = null;
        //执行目标方法
        obj = joinPoint.proceed();
        System.out.println("退出环绕通知");
        return obj;
    }
}

Spring AOP实现原理

Spring AOP是基于动态代理实现的,因此Spring对AOP的支持局限于方法级别的拦截。

动态代理:如上图所示,调用者不能直接发送请求给目标对象,而是先发送给代理类,代理类在给你转发到目标对象。

代理的生成时期:织入

Spring AOP的代理生成时期是"运行期",动态的织入字节码

Spring框架中的AOP实现方式有两种1.JDK proxy方式;2.CGLIB方式。在Spirng中默认是JDK方式,而在Spring boot中是CGLIB。

JDK实现要求被代理类必须实现接口,而CGLIB没有这个要求,是通过继承被代理类,所以被final修饰的代理类,无法被继承,只能选择JDK.

相关推荐
风铃儿~7 小时前
Spring AI 入门:Java 开发者的生成式 AI 实践之路
java·人工智能·spring
hstar952711 小时前
三十三、面向对象底层逻辑-SpringMVC九大组件之HandlerExceptionResolver接口设计
java·spring·设计模式·架构
面朝大海,春不暖,花不开11 小时前
Spring Security默认配置覆盖指南
java·后端·spring
IT_Octopus13 小时前
多线程下使用缓存+锁Lock, 出现“锁失效” + “缓存未命中竞争”的缓存击穿情况,双重检查缓存解决问题
java·spring·缓存
qq_3380329218 小时前
Spring Boot/Spring应用中配置自定义RedisTemplate
spring boot·redis·spring
考虑考虑19 小时前
Springboot3.5.x版本actuator新属性
spring boot·后端·spring
萌新小码农‍1 天前
Spring框架学习day7--SpringWeb学习(概念与搭建配置)
学习·spring·状态模式
Mr Aokey1 天前
Spring MVC参数绑定终极手册:单&多参/对象/集合/JSON/文件上传精讲
java·后端·spring
长勺1 天前
Spring中@Primary注解的作用与使用
java·后端·spring
想用offer打牌1 天前
面试回答喜欢用构造器注入,面试官很满意😎...
后端·spring·面试