Spring AOP

目录

一. AOP 思想 和 Spring AOP

二. AOP 的组成 

三. Spring AOP 的实现 

1. 框架支持 

 2. 定义切面和切点

拦截表达式的说明 

3. 定义相关通知 

4. 创建连接点 

四. Spring AOP 的实现原理 


一. AOP 思想 和 Spring AOP

AOP 是面向切面编程,是一种思想,可以理解为对某一类事情的集中处理,例如登陆权限的校验。使用 AOP 之前,在每一处需要判断用户登录的场景的时候,都需要各自去实现调用来完成对用户登录的验证。有了 AOP 之后,就只需要在某一处进行配置,就可以对需要判断用户登录的场景进行统一处理。

AOP 是一种思想,而 Spring AOP 框架就是对 AOP 思想的一种实现,这样的关系就类似于 IOC 和 DI。

二. AOP 的组成 

1. 切面(类):理解为某一方面的具体内容,比如用户的登录判断就可以理解为是一个 "切面" ;

2. 切点(方法):理解为一个拦截规则,也就是哪一块内容需要去处理登录判断,哪一块不需要去处理用户判断;

3. 通知(方法具体实现代码):理解为执行具体的 AOP 业务逻辑;

        3.1 前置通知:在目标方法 (实际要执行的方法) 调用之前执行的通知;

        3.2 后置通知:在目标方法调用之后执行的通知;

        3.3 环绕通知:在目标方法调用前,后都会执行;(比前置通知快,比后置通知慢) 

        3.4 异常通知:在目标方法抛出异常的时候执行的通知;

        3.5 返回通知:在目标方法返回的时候执行通知;

4. 连接点: 理解为可能触发切点的点,是根据切点中的拦截规来的;

三. Spring AOP 的实现 

1. 框架支持 

Spring AOP 的框架支持需要在 maven 库中添加,在spring boot中找不到框架支持; 

<!-- 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.10</version>
		</dependency>

 2. 定义切面和切点

1. 使用 @Aspect 和五大类注解定义切面;

2. 使用@Pointcut("execution()") 注解定义切点,在 execution() 中实现拦截规则,并且定义一个空方法,不需要由方法体,主要是起到一个"标识"作用,标识下面的通知方法具体是指哪个切点。

@Aspect
@Component          // 组件
public class UserAOP {
    @Pointcut("execution(public * com.example.demo.controller.UserController.*(..))")
//    定义空方法,记住方法名
    public void pointcut(){
    }

拦截表达式的说明 

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

修饰符和异常通常可以省略;

主要涉及到三种通配符:

1. * 表示匹配任意字符,只匹配一个元素,元素可以是包,类,方法等;

2. .. 表示匹配任意字符,可以匹配多个元素,在表示类的时候,必须与 * 联合使用;

3. + 表示继承该类的所有子类包括其本身,必须跟在类名后面;

例如上述代码就表示匹配:public 修饰符下,com.example.demo.controller 包下的 UserController 类下的所有方法,不需要关注方法的参数;

3. 定义相关通知 

定义通知就是被拦截的方法具体要实现的业务逻辑。通常使用到的注解:

1. 前置通知:@Befor

2. 后置通知:@After

3. 环绕通知:@Around

4. 异常通知:@AfterThrowing

5. 返回通知: @AfterReturning

在每一个注解中,都需要说明是对于哪个切点的,对应的内容就是切点定义的方法名;


// 加两个注解变为切面
@Aspect
@Component          // 组件
public class UserAOP {
    public void pointcut(){
    }

//    前置通知
    @Before("pointcut()")
    public void doBefore(){
        System.out.println("执行了前置通知:"+ LocalDateTime.now());
    }

//    后置通知
    @After("pointcut()")
    public void doAfter(){
        System.out.println("执行了后置通知:"+ LocalDateTime.now());
    }

//    环绕通知  ProceedingJoinPoint 表示事件(方法)本身
    @Around("pointcut()")
    public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("开始执行环绕通知");             // 比前置快执行
        Object obj = proceedingJoinPoint.proceed();
        System.out.println("结束执行环绕通知");             // 比后置慢执行
        return obj;
    }
}

4. 创建连接点 


@RestController
public class UserController {
    @RequestMapping("/user")
    public Object sayHi(){
        System.out.println("执行了 sayHi 方法");
        return "hello";
    }

    @RequestMapping("user2")
    public Object sayHi2(){
        System.out.println("执行了 sayHi2 方法");
        return "hello2";
    }
}

四. Spring AOP 的实现原理 

Spring AOP 是一种框架,针对 AOP 面向切面的一种实现。构建在动态代理的基础上的,基于动态代理实现的;

通过动态代理来实现,就可以理解为程序为了实现某一种功能做了某一层筛选,而这一层筛选,就是通过代理来实现的,这时候,也就不需要每种具体功能实现都由目标对象来实现了。

在没有实现代理类的时候,是调用者直接去调用目标对象,这意味着目标对象此时需要做更多的事情,例如目标对象是添加文章,在添加文章之前需要做登录校验,如果有了动态代理,代理对象此时可以为调用者进行登录校验,此时目标对象可以不用直接和调用者接触,动态代理可以为我们作出信息筛选,只有条件满足了,才会将到目标对象去执行,不满足就直接返回了,此时对于目标对象,可以专注与做添加文章的操作,而不需要为别的事情考虑,别的事情交给代理对象来完成即可。

Spring AOP 支持 JDK Proxy 和 CGLIB 的方式实现动态代理,JDK是基于接口实现的,CGLIB是基于类的子类实现的; 

JDK 动态代理底层是通过反射来实现的,CGLIB底层是通过字节码增强技术生成子类实现的:例如现在有一个A类,通过一些手段来构造一个A的子类,子类又包含父类的所有属性方法,此时就可以通过子类的方法来调用父类,在大家看来这个子类是不存在的,这个子类就是通过CGLIB内库是构建的一个虚拟类,构建虚拟类的这个技术就是字节码增强技术;

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

PlLI-

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值