AOP
1.2.1 AOP说明
名称: 面向切面编程.
作用: 减少代码的耦合性,扩展业务方法.
1.2.2AOP公式
AOP切面 = 切入点(IF判断) + 通知(方法)
1.2.2.1切入点表达式
1.Bean 类的路径 类中的方法执行都会执行通知.
指定具体某一个bean
2.within(包名.类名)
within(com.jt.service.) service包中全部的类中的方法执行都会执行通知方法.
上述的2种通知粒度较粗.
3.execution(返回值类型 包名.类名.方法名(参数列表))
例子1:
execution(int com.jt.service….(…))
返回值类型int类型,com.jt.service下的所有包下的所有类
的所有方法,并且参数列表是任意的.
例子2:
execution( com..service..*(int))
返回值为任意类型 com包下的一级包路径的service包的一级包的所有类型的所有方法的参数有一个参数并且类型为int
aaa@qq.com(包名.注解名)
@annotation(注解名)
1.2.3通知类型
1.before 前置通知 目标方法执行之前执行.
2.afterReturning 后置通知 目标方法执行之后执行.
3.afterThrowing 异常通知 目标方法执行之后出现异常时执行.
4.after 最终通知 不管什么时候最后都要执行的通知.
5.around 环绕通知 目标方法执行前后都要执行的通知.
说明:around功能最为强大,因为可以控制目标方法的执行
1.2.4AOP整合案例
//@Component //将类交给spring容器管理
@Aspect
public class DemoAOP {
//切入点+通知 com.jt.service全部类全部方法 任意参数,任意返回值
@Pointcut("execution(* com.jt.service..*.*(..))")
public void pointCut() {
System.out.println("太TM随意!!!");
}
/**
* 四大通知: before/afterReturning/afterThrowing/after
* 主要记录程序的执行状态 一般不加返回值. 都是void
* afterReturning除外.
* 参数中只能添加 JoinPoint
*
*around通知最为强大 可以控制目标方法是否执行.
* 参数中必须添加ProceedingJoinPoint
*/
/**
* 获取目标对象的name
*/
@Before("pointCut()")
public void before(JoinPoint joinPoint) {
String targetName =
joinPoint.getSignature().getDeclaringTypeName();
System.out.println("我是一个before通知:"+targetName);
}
//目标方法执行之后
@AfterReturning(pointcut = "pointCut()",returning = "obj")
public Object afterReturn(Object obj) {
System.out.println(obj);
System.out.println("我是一个傻傻的后置通知!!!!");
return obj;
}
//异常通知和后置通知是互斥的
@AfterThrowing(pointcut = "pointCut()",throwing = "thro")
public void afterThrow(Exception thro) {
System.out.println("我是一个异常通知!!!!!");
System.out.println(thro.getMessage());
}
@Around("pointCut()")
public Object around(ProceedingJoinPoint joinPoint) {
Object obj = null;
try {
Long startTime = System.currentTimeMillis();
System.out.println("环绕通知执行前");
obj = joinPoint.proceed();
Long endTime = System.currentTimeMillis();
System.out.println("方式执行时间:"+(endTime - startTime));
} catch (Throwable e) {
e.printStackTrace();
}
return obj;
}
}
1.2.5AOP图解
1.前置通知
2.后置通知
3.环绕通知
1.3利用AOP实现缓存处理
1.3.1缓存实现准备
1.通知选择 环绕通知
2.切入点表达式 自定义缓存注解,实现该操作.
3.自定义注解CacheFind
1.3.2编辑自定义注解
@Target(ElementType.METHOD) //该注解对方法有效
@Retention(RetentionPolicy.RUNTIME) //表示运行期有效
public @interface CacheFind {
//保存到redis中 key value 用户可以自己指定,也可以动态生成
public String key() default "";
public int seconds() default 0; //设定超时时间秒
}
1.3.3编辑AOP切面
@Component
@Aspect
public class CacheAOP {
@Autowired(required = false)//必须添加参数
private Jedis jedis;
/**
* 思考: 是否需要获取注解中的参数.
* 需要: 切入点表达式中写注解名称
* 不需要: 如果只是做标识,使用包名.注解名
*
* key的生成策略:
* 包名.类名.方法名::第一个参数parentId
*
* 缓存实现业务:
* 1.从redis中查询数据 获取结果result
* 2. result==null 用户第一次查询. 执行目标方法
* 将返回值结果转为JSON.之后保存到redis.
* 根据seconds判断是否超时 redis.set redis.setex
* 3. result !=null
* 直接将json数据转化为 返回值对象.
* @param joinPoint
* @return
*/
@Around("@annotation(cacheFind)")
public Object around(ProceedingJoinPoint joinPoint,
CacheFind cacheFind) {
//动态获取key的值
String key = getKey(joinPoint,cacheFind);
//1.获取缓存数据
String result = jedis.get(key);
Object obj = null;
try {
if(StringUtils.isEmpty(result)) {
System.out.println("AOP查询数据库操作!!!");
//说明用户第一次查询. 执行目标方法
obj = joinPoint.proceed();
//2.数据保存到redis中
String json = ObjectMapperUtil.toJSON(obj);
if(cacheFind.seconds()>0)
jedis.setex(key, cacheFind.seconds(), json);
else
jedis.set(key, json);
}else {
//result为json数据,需要转化为对象
//目标方法返回值类型
Class<?> returnType = getReturnType(joinPoint);
obj =
ObjectMapperUtil.toObj(result, returnType);
System.out.println("AOP查询缓存!!!!");
}
} catch (Throwable e) {
e.printStackTrace();
throw new RuntimeException(e);
}
return obj;
}
/**
* 策略: 如果用户自己指定了key,
* 则使用用户的,如果没有指定则动态生成.
* @param joinPoint
* @param cacheFind
* @return
*/
private String getKey(ProceedingJoinPoint joinPoint, CacheFind cacheFind) {
//1.获取用户自己的参数
String key = cacheFind.key();
//2.判断key是否有效
if(!StringUtils.isEmpty(key)) {
return key;
}
//3.如果用户没有传递,则动态生成 方法的API
Signature signature = joinPoint.getSignature();
String className = signature.getDeclaringTypeName();
String methodName = signature.getName();
Long arg0 = (Long) joinPoint.getArgs()[0]; //Long
key = className+"."+methodName+"::"+arg0;
return key;
}
private Class<?> getReturnType(ProceedingJoinPoint joinPoint) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature(); //方法签名对象
return signature.getReturnType();
}
//记录一下程序的执行时间 环绕通知
}
上一篇: Spring AOP原理解析——基于自动代理AOP是如何实现的?
下一篇: 员工管理系统