Spring AOP 的实现及原理

目录

  • [什么是 Spring AOP ?](#什么是 Spring AOP ?)
    • [AOP 是啥 ?](#AOP 是啥 ?)
    • [Spring AOP 可以干啥 ?](#Spring AOP 可以干啥 ?)
  • [AOP 的组成](#AOP 的组成)
  • [Spring AOP 的实现](#Spring AOP 的实现)
  • [Spring AOP 的实现原理](#Spring AOP 的实现原理)

什么是 Spring AOP ?

AOP 是啥 ?

我们知道 OOP 是面向对象编程, 那 AOP 又是啥呢 ?

AOP(Aspect Oriented Programming):⾯向切⾯编程,它是⼀种思想,它是对某⼀类事情的集中处理。

什么又是面向切面编程?

就比如:我上 CSDN 发布文章时,它会先查询我的登录状态,我查询个人文章列表时,也要查询登录状态,查看个人主页也一样,这些功能的共同点是查询登录状态,那判断用户是否登录这件事,它就是一个切面,他就是某一类事,面向切面编程就是面向某一类事进行编程,将某一类事集中处理了。(这样就可以把精力放在业务逻辑上,而不是编写重复代码)

AOP 是⼀种思想,⽽ Spring AOP 是⼀个框架,提供了⼀种对 AOP 思想的实现,它们的关系和 IoC 与 DI 类似。

Spring AOP 可以干啥 ?

统一用户登录判断

统一日志记录

统一方法执⾏时间统计

统⼀的返回格式设置

统⼀的异常处理

事务的开启和提交等等

AOP 是针对某一类通用的事件进行统一处理,它是 OOP 的一种补充。

AOP 的组成

  1. 切面 (Aspect):定义的是什么事件(AOP 是干什么的,比如:是用户登录校验)

  2. 切点 (Pointcut):定义具体规则(定义用户拦截规则,比如:哪些接口需要判断用户登录,哪些接口不需要判断)

  3. 通知 (Advice):AOP 执行的具体方法(比如:获取用户登录信息,获取到则说明已登录)

通知又分为以下几种:

前置通知 @Before:通知⽅法会在⽬标⽅法调⽤之前执⾏。

后置通知 @After:通知⽅法会在⽬标⽅法返回或者抛出异常后调⽤。

返回通知 @AfterReturning:通知⽅法会在⽬标⽅法返回后调⽤。

异常通知 @AfterThrowing:通知⽅法会在⽬标⽅法抛出异常后调⽤。

环绕通知 @Around:通知包裹了被通知的⽅法,在被通知的⽅法通知之前和调⽤之后执行自定义的行为。

  1. 连接点 (Join Point):所有可能触发切点的点(比如:所有接口)

Spring AOP 的实现

  1. 添加 Spring AOP 依赖:
java 复制代码
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-bo
ot-starter-aop -->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
  1. 定义切面:
java 复制代码
@Aspect  //表明此类为一个切面
@Component   // 随着spring框架启动而启动
public class UserAspect {
 
}
  1. 定义切点:
java 复制代码
@Aspect  //表明此类为一个切面
@Component   // 随着spring框架启动而启动
public class UserAspect {
	// 切点,这⾥使⽤ AspectJ 表达式语法
	//拦截 UserController 里所有方法
    @Pointcut("execution(* com.example.demo.controller.UserController.* (..))")
    public void pointcut(){   
    }
}
  1. 执行通知:

先将被拦截的类实现:

java 复制代码
@RestController
@RequestMapping("/user")
public class UserController {

    @RequestMapping("/getuser")
    public String getUser() {
        System.out.println("do getUser");
        return "get User";
    }

    @RequestMapping("/deluser")
    public String delUser() {
        System.out.println("do delUser");
        return "del User";
    }
}
java 复制代码
@Aspect  
@Component   
public class UserAspect {
    @Pointcut("execution(* com.example.demo.controller.UserController.* (..))")
    public void pointcut(){
    }

    //该前置通知针对于这个切点
    @Before("pointcut()")
    public void doBefore() {
        System.out.println("执行了前置通知");
    }
}


确实是先执行前置通知,再执行被拦截的方法。

再来执行个后置通知:

java 复制代码
    @After("pointcut()")
    public void doAfter() {
        System.out.println("执行了后置通知");
    }

再次访问:

环绕通知:

java 复制代码
    // 添加环绕通知
    @Around("pointcut()")
    public Object doAround(ProceedingJoinPoint joinPoint){
        Object obj = null;
        System.out.println("Around ⽅法开始执⾏");
        try {
            // 执⾏目标⽅法
            obj = joinPoint.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        System.out.println("Around ⽅法结束执⾏");
        return obj;
    }


环绕通知是在最前面和最后面执行的。(在多线程中可以统计目标方法的执行时间,单线程下也可以使用前置通知和后置通知来统计)

Spring AOP 的实现原理

Spring AOP 是构建在动态代理基础上,因此 Spring 对 AOP 的⽀持局限于⽅法级别的拦截。

Spring 动态代理组成:

  1. JDK Proxy(代理对象必须实现接口,才能使用 JDK Proxy)

  2. CGLIB(通过实现代理类的子类来实现动态代理,被 final 修饰的类不能被代理)
    JDK Proxy 和 CGLIB 区别:

  3. 实现不同:DK Proxy 要求代理类实现接口才能被代理,CGLIB 通过实现代理类的子类来实现动态代理

  4. 性能不同:JDK 7+ JDK Proxy 的性能高于 CGLIB,JDK 7 前则低于

相关推荐
程序员张33 小时前
Maven编译和打包插件
java·spring boot·maven
ybq195133454314 小时前
Redis-主从复制-分布式系统
java·数据库·redis
weixin_472339464 小时前
高效处理大体积Excel文件的Java技术方案解析
java·开发语言·excel
灵犀学长4 小时前
EasyExcel之SheetWriteHandler:解锁Excel写入的高阶玩法
spring boot·excel
小毛驴8505 小时前
Linux 后台启动java jar 程序 nohup java -jar
java·linux·jar
zwjapple5 小时前
docker-compose一键部署全栈项目。springboot后端,react前端
前端·spring boot·docker
DKPT5 小时前
Java桥接模式实现方式与测试方法
java·笔记·学习·设计模式·桥接模式
好奇的菜鸟7 小时前
如何在IntelliJ IDEA中设置数据库连接全局共享
java·数据库·intellij-idea
DuelCode8 小时前
Windows VMWare Centos Docker部署Springboot 应用实现文件上传返回文件http链接
java·spring boot·mysql·nginx·docker·centos·mybatis
优创学社28 小时前
基于springboot的社区生鲜团购系统
java·spring boot·后端