AOP:
AOP=通知方法(写在切面中,@Aspect注解的类)+切入点表达式
通知方法
1.before通知 在执行目标方法之前执行
2.afterReturning通知 在目标方法执行之后执行
3.afterThrowing通知 在目标方法执行之后报错时执行
4.after通知 无论什么时候程序执行完成都要执行的通知
上述的4大通知类型,不能控制目标方法是否执行.一般用来记录程序的执行的状态.
一般应用与监控的操作.
5.around通知(功能最为强大的) 在目标方法执行前后执行.
因为环绕通知可以控制目标方法是否执行.控制程序的执行的轨迹.
切入点表达式
1.bean(“bean的ID”) 粒度: 粗粒度 按bean匹配 当前bean中的方法都会执行通知.
2.within(“包名.类名”) 粒度: 粗粒度 可以匹配多个类
3.execution(“返回值类型 包名.类名.方法名(参数列表)”) 粒度: 细粒度 方法参数级别
4.@annotation(“包名.类名”) 粒度:细粒度 按照注解匹配
JoinPoint 对象常用API
方法名 | 功能 |
---|---|
point.getSignature() | 封装了被注解所修饰的方法所在类的信息,得到的是方法签名(方法名和参数类型) |
point.getTarget() | 封装了被注解所修饰的方法的信息 |
point.getArgs() | 封装了被注解所修饰的方法的参数信息 |
point.getSignature().getName() | 被修饰的方法的方法名 |
point.getSignature().getMethod() | 封装了被修饰的方法的信息 |
package com.jt.aop;
import com.jt.annotation.CacheFind;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.Arrays;
@Slf4j
@Aspect
@Component
public class CacheAop {
@Around("@annotation(com.jt.annotation.CacheFind)")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
//目标对象的Class类型
Class targetClass=joinPoint.getTarget().getClass();
System.out.println("joinPoint.getTarget()-->"+joinPoint.getTarget());
System.out.println("targetClass-->"+targetClass);
//目标对象的方法名
String methodName=joinPoint.getSignature().getName();
System.out.println("joinPoint.getSignature()-->"+joinPoint.getSignature());
System.out.println("methodName-->"+methodName);
//获取参数类型
Object[] argsObj=joinPoint.getArgs();
System.out.println("argsObj-->"+argsObj);
System.out.println("argsObj-->"+Arrays.toString(argsObj));
Class[]argsClass=null;
//对象转化为class类型
if(argsObj.length>0){
argsClass=new Class[argsObj.length];
for(int i=0;i<argsObj.length;i++){
argsClass[i]=argsObj[i].getClass();
}
}
//获取方法对象
Method targetMethod=targetClass.getMethod(methodName,argsClass);
System.out.println("targetMethod-->"+targetMethod);
//获取方法上注解
if(targetMethod.isAnnotationPresent(CacheFind.class)){
CacheFind cacheFind=targetMethod.getAnnotation(CacheFind.class);
String key=cacheFind.preKey()+"::"+Arrays.toString(joinPoint.getArgs());
System.out.println("key-->"+key);
}
Object result=joinPoint.proceed();
return result;
}
}
输出结果
joinPoint.getTarget()-->com.jt.service.ItemCatServiceImpl@1030359b
targetClass-->class com.jt.service.ItemCatServiceImpl
joinPoint.getSignature()-->List com.jt.service.ItemCatServiceImpl.findItemCatList(Long)
methodName-->findItemCatList
argsObj-->[Ljava.lang.Object;@465014a7
argsObj-->[0]
targetMethod-->public java.util.List com.jt.service.ItemCatServiceImpl.findItemCatList(java.lang.Long)
key-->ITEMCAT_PARENTID::[0]
@Around("@annotation(cacheFind)")
/**
* @Around("@annotation(cacheFind)"),里面虽然是"cacheFind",但是框架会自动搜索,
* 搜索到下面的方法后,会找到大写的"CacheFind",路径是"com.jt.annotation.CacheFind"
* 因此编译的时候,虽然写的是"@Around("@annotation(cacheFind)")",但是实际编译的还是
* "@Around("@annotation(com.jt.annotation.CacheFind)")"
*/
public Object around(ProceedingJoinPoint joinPoint,CacheFind cacheFind) throws Throwable {
String preKey=cacheFind.preKey();
String key=preKey+"::"+Arrays.toString(joinPoint.getArgs());
Object result=null;
if (jedis.exists(key)){
String json=jedis.get(key);
//获取方法对象
//MethodSignature 是getSignature的子类
MethodSignature methodSignature=(MethodSignature) joinPoint.getSignature();
//获取方法返回值类型
Class returnType=methodSignature.getReturnType();
result=ObjectMapperUtil.toObj(json,returnType);
}else{
result=joinPoint.proceed();
String json= ObjectMapperUtil.toJson(result);
if(cacheFind.seconds()>0){
jedis.setex(key, cacheFind.seconds(), json);
}else{
jedis.set(key, json);
}
}
return result;
}