SpringAOP
SpringAOP的切点
面向切面,即在一个切点前后执行某些操作。
切点定义格式:
例如定义test包下Controller的test()方法为一个切点:
@Pointcut("execution(* test.AppController.test(*))")
public void pointCut(){}
SpringAOP定义了5种通知:
通知 | 描述 |
---|---|
前置通知 | 在一个方法执行之前,执行通知。 |
后置通知 | 在一个方法执行之后,不考虑其结果,执行通知。 |
返回后通知 | 在一个方法执行之后,只有在方法成功完成时,才能执行通知。 |
抛出异常后通知 | 在一个方法执行之后,只有在方法退出抛出异常时,才能执行通知。 |
环绕通知 | 在建议方法调用之前和之后,执行通知。 |
对应格式(引用于https://www.w3cschool.cn/wkspring/k4q21mm8.html):
@Before("pointCut()")
public void doBeforeTask(){
...
}
@After("businessService()")
public void doAfterTask(){
...
}
@AfterReturning(pointcut = "businessService()", returning="retVal")
public void doAfterReturnningTask(Object retVal){
// you can intercept retVal here.
...
}
@AfterThrowing(pointcut = "businessService()", throwing="ex")
public void doAfterThrowingTask(Exception ex){
// you can intercept thrown exception here.
...
}
@Around("pointcut()")
public void doAroundTask(){
...
}
利用SpringAOP和redis做缓存(基于SpringBoot)
缓存策略:
利用环绕通知,在且点前查询redis,若存在,则直接返回查询结果,否则调用数据库查询,并将查询结果保存到redis。
切面类:
@Aspect
@Component
public class PointCutTest {
@Autowired
RedisTemplate<String,String> redisTemplate ;
@Pointcut("execution(* test.AppController.test(*))")
public void pointCut(){}
@Around("pointCut()")
public Object testBefore(ProceedingJoinPoint joinPoint){
System.out.println("查询redis...");
String id = joinPoint.getArgs()[0].toString();
System.out.println("id="+id);
Object object = null;
object = redisTemplate.opsForValue().get(id);
if (object!=null) {
System.out.println("redis获取到缓存,直接返回");
return JSONObject.fromObject(object).toString();
}
System.out.println("redis未找到缓存结果,调用数据库查询...");
try {
object = joinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
if(object!=null){
System.out.println("数据库查询成功,保存到缓存中...");
redisTemplate.opsForValue().set(id, JSONObject.fromObject(object).toString());
}
System.out.println("查询完成");
return object;
}
}
被切类:(为了方便没有真的查数据库)
@Controller
public class AppController {
@Autowired
RedisTemplate<String,String> redisTemplate ;
@ResponseBody
@RequestMapping("/")
public String test(int id){
Stu stu = new Stu();
System.out.println("模拟数据库查询...");
stu.setId(id);
stu.setName("00"+id);
return JSONObject.fromObject(stu).toString();
}
}
实体类:
@Entity
@Table(name = "tb_stu")
public class Stu {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
测试:
第一次查询id为1的数据:
查询redis...
id=1
未找到缓存结果,调用数据库查询...
模拟数据库查询...
数据库查询成功,保存到缓存中...
查询完成
第二次查询id为1的数据:
查询redis...
redis id=1
获取到缓存,直接返回
完成。