Redis实现1--day11

1.商品分类缓存实现

1.当用户点击商品分类按钮时开始获取服务端数据.
2.先查询redis缓存是否有数据
3.如果redis中没有数据,则查询数据库.之后将查询的结果保存到redis中
4.如果redis中有数据,则直接返回缓存记录.

思路:
准备String key =“ITEM_CAT_LIST::”+parentId
准备value="JSON"串
首先查询redis缓存
有:返回数据
没有:查询数据库,并返回缓存和数据

1.1编辑ItemCatController 修改findItemCatByParentId方法

	@RequestMapping("/list")
	public List<EasyUITree> findItemCatByParentId(@RequestParam(value = "id",defaultValue = "0")Long parentId) {
		//通过缓存的方式获取数据
		return itemCatService.findItemCatByCache(parentId);
	}

1.2在ItemCatServiceImpl添加方法

	//spring容器初始化时,(required=false)该注解不是必须注入,但是如果程序调用则必须有值
	@Autowired(required=false)  
	private Jedis jedis;

	/**
	 * 通过缓存的方式查询数据库.
	 * 1).定义key
	 * 2).根据key查询redis.
	 */
	@SuppressWarnings("unchecked")
	@Override
	public List<EasyUITree> findItemCatByCache(Long parentId) {
		//1.定义key
		String key ="ITEM_CAT_LIST::"+parentId;
		List<EasyUITree> treeList =new ArrayList<EasyUITree>();
		Long startTime =System.currentTimeMillis();
		//2.判断redis是否有值
		if (jedis.exists(key)) {
			//不是第一次查询,获取缓存数据直接返回数据
			String json= jedis.get(key);
			Long endTime =System.currentTimeMillis();
			treeList = ObjectMapperUtil.toObject(json, treeList.getClass());
			System.out.println("redis查询缓存时间为:"+(endTime-startTime)+"毫秒");
			
		}else{//redis中没有key,用户第一次查询,让他去查询数据库
			treeList = findItemCatByParentId(parentId);
			Long endTime =System.currentTimeMillis();
			//需要将list集合转化为json(调用ObjectMapperUtilAPI)
			String json= ObjectMapperUtil.toJSON(treeList);
			//将数据保存到redis中
			jedis.set(key, json);
			System.out.println("redis查询数据库时间为:"+(endTime-startTime)+"毫秒");
		}
		
		return treeList;
	}

1.3速度测试

在这里插入图片描述

2.利用AOP实现redis缓存

2.1传统项目弊端

说明:
1).由于将redis的操作写到service层中,必须导致业务的耦合性高
2).如果采用上述的方式完成缓存,则改缓存不通用,并且代码冗余.效率低.

2.2 AOP的核心理念

在这里插入图片描述
公式: AOP = 切入点表达式 + 通知方法

2.3 切入点表达式

1). bean(bean的ID) 按照指定的bean名称拦截用户的请求,之后执行通知方法. 只能匹配单个bean对象
2).within(包名.类名) 可以按照类通配的方式去拦截用户的请求. 控制粒度较粗.
3).execution(返回值类型 包名.类名.方法名(参数列表)) 方法参数级别 控制粒度较细
4).@annotation(包名.注解名称) 按照注解的方式去拦截用户请求.

2.4 通知方法

1.前置通知: 主要在 目标方法执行之前执行
2.后置通知: 在目标方法执行之后执行
3.异常通知: 在目标方法执行的过程中报了异常之后执行.
4.最终通知: 无论什么时候都要执行的通知方法.
上述的通知方法,无法控制目标方法是否执行.所以一般"只做记录不做改变"
5.环绕通知: 一般采用环绕通知 实现对业务的控制.

2.5 AOP入门案例

package com.jt.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

//1.将对象交给容器管理
@Component
//2.定义AOP切面
@Aspect
public class CacheAOP {
	
	//公式:  切面=切入点表达式+通知方法.
	/**
	 * 业务需求:要求拦截ItemCatServiceImpl类中的业务方法
	 * @Pointcut 切入点表达式  可以理解为一个if判断,只有满足条件(在itemCatServiceImpl类中)才可以执行方法
	 */
	
	//@Pointcut("bean(itemCatServiceImpl)")  //按类匹配,控制的力度较粗   单个bean
	//@Pointcut("within(com.jt.service.*)") //按类匹配,控制的力度较粗  多个bean
	 @Pointcut("execution(* com.jt.service..*.*(..))") //细粒度的匹配方式
	 @Pointcut("@annotation(com.jt.anno.CacheFind)")  //拦截注解  		//不需要获取注解里的内容用这个方法
	public void pointCut() {
	
	}
	
	//JoinPoint 	方法执行切恰好被切入点表达式匹配,该方法的执行就称之为连接点.
	//@Before("bean(itemCatServiceImpl)")				//一个切入点本次用
	@Before("pointCut()")		//前置通知(绑定切入点表达式)//一个切入点可以共同使用
	public void before(JoinPoint joinpoint) {
		System.out.println("前置通知(绑定切入点表达式)");
		String typeName=
				joinpoint.getSignature().getDeclaringTypeName();
		String methodName=joinpoint.getSignature().getName();
		System.out.println("方法的全路径为:"+typeName+"."+methodName);
		Object[] obj=joinpoint.getArgs();
		System.out.println("获取方法参数:"+obj);
		Object target =joinpoint.getTarget();
		System.out.println("获取目标对象:"+target);
	}
	//添加环绕通知
	@Around("pointCut()")
	public Object around(ProceedingJoinPoint joinPoint) {
		
		System.out.println("我是环绕通知开始");
		try {
			Object result = joinPoint.proceed();
			System.out.println("我是环绕通知结束");
			return result;
		} catch (Throwable e) {
			e.printStackTrace();
			throw new RuntimeException();
		}
	}
}

2.6实现AOP缓存处理

package com.jt.anno;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)				//对谁有效
@Retention(RetentionPolicy.RUNTIME)		//有效期
public @interface CacheFind {
	public String key();	//标识存入redis的key的前缀
	public int secondes() default 0;	//标识保存时间  单位秒
}

2.6.1标识注解

在这里插入图片描述

2.6.2修改CacheAOP

package com.jt.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.jt.anno.CacheFind;
import com.jt.util.ObjectMapperUtil;

import redis.clients.jedis.Jedis;

//1.将对象交给容器管理
@Component
//2.定义AOP切面
@Aspect
public class CacheAOP {
	
	@Autowired(required=false)
	private Jedis jedis;
	/**
	 * 实现思路: 拦截被@CacheFind标识的方法之后利用AOP进行缓存的控制
	 * 通知方法: 环绕通知
	 * 实现步骤:
	 * 		1.准备查询redis的key   ITEM_CAT_LIST::第一个参数
	 * 		2.("@annotation(cacheFind)")动态获取注解的语法.
	 * 		拦截指定注解类型的注解并且将注解对象当做参数进行传递.
	 */
	@SuppressWarnings("unchecked")		//压制警告
	//@Around("@annotation(com.jt.anno.CacheFind)")
	@Around("@annotation(cacheFind)")		//动态获取注解的语法
	public Object around(ProceedingJoinPoint joinPoint,CacheFind cacheFind) {
		//1.获取用户注解中的key   ITEM_CAT_LIST
		String key =cacheFind.key();
		
		//2.动态获取第一个参数当做key
		
		//joinPoint.getArgs()  获取目标方法的参数|[0]第一个参数Long parentId
		Object firstArg=joinPoint.getArgs()[0].toString();
		key +="::"+firstArg;
		Object result = null;
		
		//3.根据key查询redis
		if(jedis.exists(key)) {
			//根据redis获取信息
			String  json=jedis.get(key);
			MethodSignature methodSignature=(MethodSignature) joinPoint.getSignature();//getSignature得到方法对象的参数
			result = ObjectMapperUtil.toObject(json,methodSignature.getReturnType());
			System.out.println("aop查询redis缓存");
			
		}else {
			//如果key不存在,则证明是第一次查询,应该查询数据库
			try {
				result=joinPoint.proceed();
				System.out.println("aop查询数据库获取返回值");
				//将数据保存到redis中
				String json = ObjectMapperUtil.toJSON(result);
				int seconds=cacheFind.secondes();
				if(seconds>0)
				jedis.setex(key, seconds, json);
				else
				jedis.set(key, json);
			}catch(Throwable e){
				e.printStackTrace();
			}
		}	
		return result;
	}
}
	

2.6.3修改ItemCatServiceImpl

实现商品列表查询时的缓存处理。
在这里插入图片描述

2.6.4 AOP和代理的关系

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/SkyCloud_/article/details/107424624