spring aop aspect + annotation实现缓存命中判断

本文介绍了一种通过Spring AOP和注解实现缓存命中判断的方法,首先引入了相关依赖,然后详细展示了如何在CacheService中应用。利用JoinPoint和ProceedingJoinPoint,可以在环绕通知中获取目标方法信息并执行proceed()进行目标方法调用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    最近看到了一种使用aop和注解的方式实现缓存命中判断的实现方式,觉得非常不错。借鉴过来,进行分享。

    1、引入spring和aspect相关依赖

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>1.8.6</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
   <version>1.8.6</version>
</dependency>
<dependency>
    <groupId>aopalliance</groupId>
    <artifactId>aopalliance</artifactId>
    <version>1.0</version>
</dependency>

2、创建Cache注解类,用于标识需要添加缓存的方法。

@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Cache {
    //缓存时间,默认60秒
    int expire() default 60;

    //缓存实体类型
    Class<?> clazz();

    //缓存中存放的具体类型
    CacheType cacheType();

}

3、创建CacheType类,标识缓存的类型,目前仅有Object和List两种,其他的可以根据项目的需求自己添加。

public enum CacheType {
    OBJECT,
    LIST,
    ;
}

4、创建Cache切面类,用于解析Cache注解,实现缓存命中判断。

public class CacheAspect {

    private Logger logger = LoggerFactory.getLogger(CacheAspect.class);

    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        MethodSignature ms = (MethodSignature)pjp.getSignature();
        Method method = ms.getMethod();
        Cache annotation = method.getAnnotation(Cache.class);

        //获取注解信息
        int expire = annotation.expire();
        Class<?> clazz = annotation.clazz();
        CacheType cacheType = annotation.cacheType();

        //获取类名、方法名、参数名
        String className = pjp.getTarget().getClass().getSimpleName();
        String methodName = pjp.getSignature().getName();
        Object[] args = pjp.getArgs();
        StringBuffer sb = new StringBuffer();
        for(Object arg : args) {
            if(arg != null) {
                sb.append("_").append(arg.toString());
            }
        }
        //用类名、方法名、参数名作为缓存的key
        String cacheKey = className.concat("_").concat(methodName).concat(sb.toString());
        Object obj = CacheUtils.getFromCache(cacheKey, clazz, cacheType);
        //命中缓存,直接返回信息
        if(obj != null) {
            logger.info("cache hit for key:"+cacheKey);
            return CallResult.success(obj);
        } else {
            //未命中缓存,查询结果,并放到缓存中
            CallResult result = (CallResult)pjp.proceed();
            if(result.isSuccess()) {
                logger.info("put to cache for key:"+cacheKey);
                CacheUtils.put2Cache(cacheKey, result.getResultObject(), expire);
            }
            return result;
        }
    }
}

5、缓存添加、获取实现类,该例子仅使用内存作为缓存,在实际的项目中,可能会使用redis、memcache等缓存。

public class CacheUtils {

    private static Logger logger = LoggerFactory.getLogger(CacheUtils.class);

    private static ConcurrentHashMap<String, String> map = new ConcurrentHashMap<String, String>();

    public static void put2Cache(String key, Object result, int expire) {
        String str = JSON.toJSONString(result);
        map.put(key, str);
    }

    public static Object getFromCache(String key, Class clazz, CacheType cacheType) {
        try {
            String result = map.get(key);
            if(StringUtils.isNotBlank(result)) {
                if(CacheType.LIST.equals(cacheType)) {
                    List list = JSON.parseObject(result, List.class);
                    List retList = new ArrayList();
                    for(Object obj : list) {
                        retList.add(JSON.parseObject(obj.toString(), clazz));
                    }
                    return retList;
                } else {
                    return JSON.parseObject(result, clazz);
                }
            }
        } catch (Exception e) {
            logger.error("getFromCache exception",e);
        }
        return null;
    }
}

6、spring配置文件:

<aop:aspectj-autoproxy proxy-target-class="true" />

<bean id="cacheService" class="com.demo.lizhy.service.impl.CacheServiceImpl" />

<bean id="cacheAspect" class="com.demo.lizhy.service.aspect.CacheAspect" />
<aop:config>
    <aop:aspect ref="cacheAspect">
        <aop:around method="<strong>doAround</strong>" pointcut="@annotation(com.demo.lizhy.service.aspect.Cache)" />
    </aop:aspect>
</aop:config>

<aop:aspectj-autoproxy />有一个proxy-target-class属性,默认为false,表示使用jdk动态代理织入增强,当配为<aop:aspectj-autoproxy  poxy-target-class="true"/>时,表示使用CGLib动态代理技术织入增强。不过即使proxy-target-class设置为false,如果目标类没有声明接口,则spring将自动使用CGLib动态代理。

7、实际使用:CacheService

public class CacheServiceImpl implements CacheService {
    private Logger logger = LoggerFactory.getLogger(CacheServiceImpl.class);
    @Override
    @Cache(expire = 100, clazz = String.class, cacheType = CacheType.OBJECT)
    public CallResult<String> getCacheInfo(String name) {
        logger.info("search from db=========");
        return CallResult.success(name);
    }
}


注意:

JoinPoint:提供访问当前被通知方法的目标对象、代理对象、方法参数等数据:

ProceedingJoinPoint:用于环绕通知,使用proceed()方法来执行目标方法:


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值