56_AOP
创始人
2024-11-15 02:04:05

AOP使用案例

如何进行数据库和Redis中的数据同步?/ 你在项目的那些地方使用了aop?
答:可以通过Aop操作来实现数据库和Redis中的数据同步。/ 通过Aop操作来实现数据库和Redis中的数据同步。
可以定义一个切面类,通过对控制器下的所有方法进行环绕通知。
数据同步有两种情况

  1. 一种是服务器接收get请求,首先从Redis中取,没有对应的key再执行方法从数据库中获取数据并添加到Redis中;
  2. 第二种情况是服务器接收写请求,包括增删改,这时就需要先对Redis中的数据进行扫描,对特定key对应的的数据进行删除清空,再执行方法修改数据库中的内容(没有考虑再次将数据库中的数据同步到Redis是因为:如果服务器接收到任一get请求,都会自动进行同步)
import cn.cnmd.redis.RedisService; import com.alibaba.fastjson2.JSON; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.Signature; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping;  import java.lang.reflect.Method; import java.time.Duration; import java.util.List; import java.util.Random; import java.util.concurrent.TimeUnit;  @Aspect @Component public class RedisCacheAspect {  	private static Random random = new Random();  	@Autowired 	private RedisService redisService;  	@Pointcut("execution(* cn.ctmd.electric.*.controller.*(..))") 	private void pointcut() { 	}  	@Around("pointcut()") 	public Object around(ProceedingJoinPoint pjp) throws Throwable { 		Signature signature = pjp.getSignature(); 		MethodSignature methodSignature = (MethodSignature) signature;  		Method method = methodSignature.getMethod(); 		String className = method.getDeclaringClass().getSimpleName(); 		String methodName = method.getName(); 		if (method.isAnnotationPresent(GetMapping.class)) {// get请求 			Object[] args = pjp.getArgs(); 			String cacheKey = className + "::" + methodName + JSON.toJSONString(args); 			if (Boolean.TRUE.equals(redisService.hasKey(cacheKey))) { 				return redisService.get(cacheKey); 			} else { 				synchronized (this) { 					if (Boolean.FALSE.equals(redisService.hasKey(cacheKey))) { 						Object value = pjp.proceed(); 						long expireTime = Duration.ofMinutes(5).toMillis() + random.nextInt(1000); 						redisService.set(cacheKey, value, expireTime, TimeUnit.MILLISECONDS); 						return value; 					} else { 						return redisService.get(cacheKey); 					} 				} 			} 		} else { 			if (method.isAnnotationPresent(PostMapping.class) || method.isAnnotationPresent(PutMapping.class) || method.isAnnotationPresent(DeleteMapping.class)) { 				List list = redisService.scan(className, 50); 				if (list != null) { 					redisService.delete(list.toString()); 				} 			} 		} 		return pjp.proceed(); 	} }  

AOP

概念:面向切面编程

术语

  • 连接点:被拦截到的程序的执行点(在spring中就是被拦截到的方法)
  • 切入点:对需要进行拦截的条件的定义(某个位置)
  • 通知、增强:为切入点添加二维的功能
  • 目标对象:要被增强的对象
  • 织入:将切面和业务逻辑对象连接起来,并创建通知代理的过程
  • 代理:被织入后产生的结果类
  • 切面:一个横切关注点的模块化(一个切面类的代称)

类型

  1. 前置通知
  2. 后置通知
  3. 环绕通知
  4. 异常抛出通知
  5. 最终通知(少见)

一个切面类

@Aspect public class AspectJAdvice {      @Before(value = "execution(* com.qf.spring.aop.service..*(..))")     public void before(JoinPoint jp){         Object[] args = jp.getArgs(); //获取方法参数         Signature signature = jp.getSignature(); //获取签名         if(signature instanceof MethodSignature){ //如果签名是方法签名             Method method = ((MethodSignature) signature).getMethod(); //获取方法             String methodName = method.getName();             String className = method.getDeclaringClass().getName();             System.out.println("准备执行方法:" + className + "." + methodName + ",参数:" + Arrays.toString(args));         }     }      @AfterReturning(value = "execution(* com.qf.spring.aop.service..*(..))", returning = "returnValue")     public void after(JoinPoint jp, Object returnValue){         Object[] args = jp.getArgs(); //获取方法参数         Signature signature = jp.getSignature(); //获取签名         if(signature instanceof MethodSignature){ //如果签名是方法签名             Method method = ((MethodSignature) signature).getMethod(); //获取方法             String methodName = method.getName();             String className = method.getDeclaringClass().getName();             System.out.println("执行完方法:" + className + "." + methodName + ",参数:" + Arrays.toString(args) + ",得到返回值:" + returnValue);         }     }      @AfterThrowing(value = "execution(* com.qf.spring.aop.service..*(..))", throwing = "t")     public void exception(JoinPoint jp, Throwable t){         Object[] args = jp.getArgs(); //获取方法参数         Signature signature = jp.getSignature(); //获取签名         if(signature instanceof MethodSignature){ //如果签名是方法签名             Method method = ((MethodSignature) signature).getMethod(); //获取方法             String methodName = method.getName();             String className = method.getDeclaringClass().getName();             System.out.println("执行方法时:" + className + "." + methodName + ",参数:" + Arrays.toString(args) + ",发生了异常:" + t.getMessage());         }     }      @Around("execution(* com.qf.spring.aop.service..*(..))")     public Object around(ProceedingJoinPoint pjp) throws Throwable {         Object[] args = pjp.getArgs();//获取方法的参数         Object target = pjp.getTarget(); //获取代理对象         Signature signature = pjp.getSignature(); //获取签名         if(signature instanceof MethodSignature) { //如果签名是方法签名             Method method = ((MethodSignature) signature).getMethod(); //获取被拦截的方法对象             String methodName = method.getName();             String className = method.getDeclaringClass().getName();             try {                 System.out.println("准备执行方法:" + className + "." + methodName + ",参数:" + Arrays.toString(args));                 Object returnValue = method.invoke(target, args);                 System.out.println("执行完方法:" + className + "." + methodName + ",参数:" + Arrays.toString(args) + ",得到返回值:" + returnValue);                 return returnValue;             } catch (Throwable t){                 System.out.println("执行方法时:" + className + "." + methodName + ",参数:" + Arrays.toString(args) + ",发生了异常:" + t.getMessage());                 throw t;             }         }         return null;     } } 

相关内容

热门资讯

裸辞做“一人公司”,我后悔了 去年这个时候,一位以色列程序员正在东南亚旅行。他顺手把一个在脑子里转了很久的想法做成了产品,一个让任...
南京建成国内首个Pre-6G试... 4月21日,2026全球6G技术与产业生态大会在南京开幕。全息互动技术展台前,一名远在北京的工作人员...
超梵求职受邀参加“2025抖音... 超梵求职受邀参加“2025抖音巨量引擎成人教育行业生态大会”,探讨分享优质内容传播,服务万千学员。 ...
摩托罗拉Razr 2026(R... IT之家 4 月 22 日消息,摩托罗拉宣布新一代 Razr 折叠手机将于 4 月 29 日在美国发...
库克卸任,特纳斯领航:苹果新纪... 苹果首席执行官蒂姆·库克将卸任,硬件工程主管约翰·特纳斯将接任,苹果公司今天宣布此事。 库克将在夏季...