使用Redis+AOP优化查询性能

应用场景

在某些场景下,我们会经常查询某些特定数据,例如用户跳转各种页面都会查询用户具备该页面权限。
这种需求在流量较小的情况下没有什么问题,但如果出现大流量进行各种页面跳转的花,频繁IO对系统性能是有着非常严重的影响的。

解决方案

思路分析

由于用户具备的权限变化较少,我们完全可以将数据缓存在内存中,从而减少与磁盘的IO,提高查询效率

解决步骤

编写切面

注意笔者编码的特殊处理,由于查询时添加了中间件,为了避免redis宕机等情况导致业务查询不能正常走完流程,我们必须使用try catch进行相应捕获处理,以便后续根据情况解决问题。

package com.macro.mall.tiny.component;


import com.macro.mall.tiny.Annotation.CacheException;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;


@Aspect
@Component
public class RedisCacheAspect {
    private static Logger logger = LoggerFactory.getLogger(RedisCacheAspect.class);


    @Pointcut("execution(public * com.macro.mall.tiny.controller.*.*(..)) ")
    public void cacheAspect() {

    }

    @Around("cacheAspect()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        Object result = null;
        logger.info("通过缓存优化接口获取数据");
        try {
            result = joinPoint.proceed();
        } catch (Throwable throwable) {
           
                logger.error(throwable.getMessage());
        }
        return result;
    }


}

修改请求接口

笔者这里编码思路很简单,先去redis查,若没有再去数据查询,并存储到redis中。

@RequestMapping(value = "listAll", method = RequestMethod.GET)
    @ResponseBody
    public CommonResult<List<JSON>> getAll() throws Exception {

        List<Object> redisPmsBrandList = redisService.lRange("listAll", 0, -1);
        List<JSON> resultList = new ArrayList();
        if (null != redisPmsBrandList && redisPmsBrandList.size() > 0) {
            for (Object cacheValue : redisPmsBrandList) {
                JSON json = JSONUtil.parse(cacheValue);
                resultList.add(json);

            }
 
            return CommonResult.success(resultList);
        }
        List<PmsBrand> pmsBrands = brandService.ListAll();

        for (int i = 0; i < pmsBrands.size(); i++) {
            redisService.lPush("listAll", JSONUtil.parse(pmsBrands.get(i)));
        }

        return CommonResult.success(resultList);
    }

优化切面

现存隐患

我们一味的去捕获问题不是对错误的最佳处理,我们应该对错误进行相应归类若是业务问题导致的错误,我们需要抛出进行处理,而其他非业务的错误我们则可以进行捕获处理。所以为了能够对错误进行分类,我们可以对可能发生业务错误的方法添加一个注解标记一下。

定义标记注解
package com.macro.mall.tiny.Annotation;

import java.lang.annotation.*;

@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CacheException {
}

修改切面
@Aspect
@Component
public class RedisCacheAspect {
    private static Logger logger = LoggerFactory.getLogger(RedisCacheAspect.class);


    @Pointcut("execution(public * com.macro.mall.tiny.controller.*.*(..)) ")
    public void cacheAspect() {

    }

    @Around("cacheAspect()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        Object result = null;
        logger.info("通过缓存优化接口获取数据");
        try {
            result = joinPoint.proceed();
        } catch (Throwable throwable) {
            if (method.isAnnotationPresent(CacheException.class)) {
                logger.error("业务异常,需要排查处理");
            } else {
                logger.error(throwable.getMessage());
            }

        }
        return result;
    }


}

参考文献

使用Redis+AOP优化权限管理功能,这波操作贼爽!

你可能感兴趣的:(redis,java,spring)