问题:什么是AOP?
- AOP:面向切面编程
- 主要目的是为了解耦,相当于拦截器。
- 它可以让一组类共享相同的行为。
问题:AOP织入时机?
- 编译时织入
- AspectJ
- 类加载时织入
- AspectJ 5+ 和 AspectWerkz
- 运行时织入
- Spring AOP
问题:Spring AOP的代理模式是怎样的?
Spring AOP是动态代理:
- 如果目标对象实现了接口,则默认采用JDK动态代理
- 如果目标对象没有实现接口,则采用CGlib进行动态代理
问题:Spring AOP如何使用?
主要注解:
- @Aspect:声明一个注解,用于类上,该类必须是Bean
- @Pointcut:定义要拦截的地方(包、类、方法),支持切面表达式
- Advice:
- @Before:前置通知
- @After:最终通知,方法执行完之后
- @AfterReturning:返回通知,成功执行之后
- @AfterThrowing:异常通知,抛出异常之后
- @Around:环绕通知,包括了上面所有注解的能力
- 它具有改变拦截目标的返回值功能
问题:切面表达式如何构造?
Wildcards(通配符)
- “*”:匹配任意数量字符
- “+”:匹配指定类及其子类
- “…”:一般用于匹配任意数的子包或参数
Operators(运算符)
- “&&”:与操作符
- “||”:或操作符
- “!”:非操作符
Designators(匹配方式)
- 匹配方法
- execution()
- 匹配注解
- @target()
- @args()
- @annotation()
- 匹配包/类型
- @within()
- 匹配对象
- this()
- bean()
- target()
- 匹配参数
- args()
简单使用示例:
- 引入依赖:基于SpringBoot
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
- 构造控制器
package com.example.springaoptest.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author Miracle
* @date 2021/5/4 18:07
*/
@RestController
@RequestMapping("/test")
public class TestController {
@GetMapping("/one")
public String test1(){
return "SUCCESS";
}
}
- 构造切面:
package com.example.springaoptest;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
/**
* @author Miracle
* @date 2021/5/4 18:03
*/
@Aspect
@Component
public class AspectTest {
/**
* 设定切面拦截位置,
* 第一个“*”表示任意类
* 第二个“*”表示任意方法
* 括号内的“..”表示任意参数
*/
@Pointcut("execution(public * com.example.springaoptest.controller.*.*(..))")
public void recordLog(){
}
/**
* 进入目标方法前拦截
* @param joinPoint
*/
@Before("recordLog()")
public void recordLogBefore(JoinPoint joinPoint){
System.out.println("方法进入前执行");
}
/**
* 目标方法成功返回拦截
* @param result
*/
@AfterReturning(returning = "result" ,pointcut = "recordLog()")
public void recordLogAfter(String result){
System.out.println("方法返回值:" + result);
}
/**
* 目标方法触发异常拦截
* @param ex
*/
@AfterThrowing(throwing = "ex", pointcut = "recordLog()")
public void recordLogAfterThrow(Throwable ex){
System.out.println("方法异常:" + ex.getMessage());
}
/**
* 目标方法无论成功与否,执行完毕都触发拦截
*/
@After("recordLog()")
public void recordLogAfterFinal(){
System.out.println("方法最终执行");
}
/**
* 环绕拦截,不能与上面的注解一起使用
* @param pjp
*/
//@Around("recordLog()")
public void recordLogAround(ProceedingJoinPoint pjp){
System.out.println("环绕执行:" );
}
}
- 执行效果:
代码下载链接:
https://download.csdn.net/download/k295330167/18377318?spm=1001.2014.3001.5501