当前位置: 首页 > wzjs >正文

wordpress 首页摘要邢台市seo服务

wordpress 首页摘要,邢台市seo服务,秦皇岛建网站,江门制作手机网站引言:为什么需要声明式缓存? 背景痛点:传统代码中缓存逻辑与业务逻辑高度耦合,存在重复代码、维护困难等问题(如手动判断缓存存在性、序列化/反序列化操作) 解决方案:通过注解AOP实现缓存逻辑与…
引言:为什么需要声明式缓存?
  • 背景痛点:传统代码中缓存逻辑与业务逻辑高度耦合,存在重复代码、维护困难等问题(如手动判断缓存存在性、序列化/反序列化操作) 
  • 解决方案:通过注解+AOP实现缓存逻辑与业务解耦,开发者只需关注业务,通过注解配置缓存策略(如过期时间、防击穿机制等) 
  • 技术价值:提升代码可读性、降低维护成本、支持动态缓存策略扩展。

核心流程设计

方法调用 → 切面拦截 → 生成缓存Key → 查询Redis → 
└ 命中 → 直接返回缓存数据
└ 未命中 → 加锁查DB → 结果写入Redis → 返回数据
二、核心实现步骤
1. 定义自定义缓存注解(如@RedisCache)
package com.mixchains.ytboot.common.annotation;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.concurrent.TimeUnit;/*** @author 卫相yang* OverSion03*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RedisCache {/*** Redis键前缀(支持SpEL表达式)*/String key();/*** 过期时间(默认1天)*/long expire() default 1;/*** 时间单位(默认天)*/TimeUnit timeUnit() default TimeUnit.DAYS;/*** 是否缓存空值(防穿透)*/boolean cacheNull() default true;
}
2. 编写AOP切面(核心逻辑)
  • 切面职责

    • 缓存Key生成:拼接类名、方法名、参数哈希(MD5或SpEL动态参数)本次使用的是SpEL
    • 缓存查询:优先从Redis读取,使用FastJson等工具反序列化  
  • 空值缓存:缓存NULL值并设置短过期时间,防止恶意攻击
    package com.mixchains.ytboot.common.aspect;import com.alibaba.fastjson.JSON;
    import com.mixchains.ytboot.common.annotation.RedisCache;
    import io.micrometer.core.instrument.util.StringUtils;
    import lombok.extern.slf4j.Slf4j;
    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.core.DefaultParameterNameDiscoverer;
    import org.springframework.core.ParameterNameDiscoverer;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.expression.EvaluationContext;
    import org.springframework.expression.ExpressionParser;
    import org.springframework.expression.spel.standard.SpelExpressionParser;
    import org.springframework.expression.spel.support.StandardEvaluationContext;
    import org.springframework.stereotype.Component;import java.lang.reflect.Method;
    import java.lang.reflect.Type;/*** @author 卫相yang* OverSion03*/
    @Aspect
    @Component
    @Slf4j
    public class RedisCacheAspect {@Autowiredprivate RedisTemplate<String, String> redisTemplate;private final ExpressionParser parser = new SpelExpressionParser();private final ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();@Around("@annotation(redisCache)")public Object around(ProceedingJoinPoint joinPoint, RedisCache redisCache) throws Throwable {Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();// 解析SpEL表达式生成完整keyString key = parseKey(redisCache.key(), method, joinPoint.getArgs());// 尝试从缓存获取String cachedValue = redisTemplate.opsForValue().get(key);if (StringUtils.isNotBlank(cachedValue)) {Type returnType = ((MethodSignature) joinPoint.getSignature()).getReturnType();return JSON.parseObject(cachedValue, returnType);}// 执行原方法Object result = joinPoint.proceed();// 处理缓存存储if (result != null || redisCache.cacheNull()) {String valueToCache = result != null ?JSON.toJSONString(result) :(redisCache.cacheNull() ? "[]" : null);if (valueToCache != null) {redisTemplate.opsForValue().set(key,valueToCache,redisCache.expire(),redisCache.timeUnit());}}return result;}private String parseKey(String keyTemplate, Method method, Object[] args) {String[] paramNames = parameterNameDiscoverer.getParameterNames(method);EvaluationContext context = new StandardEvaluationContext();if (paramNames != null) {for (int i = 0; i < paramNames.length; i++) {context.setVariable(paramNames[i], args[i]);}}return parser.parseExpression(keyTemplate).getValue(context, String.class);}
    }
    

    代码片段示例

     @RedisCache(key = "'category:homeSecond:' + #categoryType",  //缓存的Key + 动态参数expire = 1, //过期时间timeUnit = TimeUnit.DAYS // 时间单位)@Overridepublic ReturnVO<List<GoodsCategory>> listHomeSecondGoodsCategory(Integer level, Integer categoryType) {// 数据库查询List<GoodsCategory> dbList = goodsCategoryMapper.selectList(new LambdaQueryWrapper<GoodsCategory>().eq(GoodsCategory::getCategoryLevel, level).eq(GoodsCategory::getCategoryType, categoryType).eq(GoodsCategory::getIsHomePage, 1).orderByDesc(GoodsCategory::getHomeSort));// 设置父级UUID(可优化为批量查询)List<Long> parentIds = dbList.stream().map(GoodsCategory::getParentId).distinct().collect(Collectors.toList());Map<Long, String> parentMap = goodsCategoryMapper.selectBatchIds(parentIds).stream().collect(Collectors.toMap(GoodsCategory::getId, GoodsCategory::getUuid));dbList.forEach(item -> item.setParentUuid(parentMap.get(item.getParentId())));return ReturnVO.ok("列出首页二级分类", dbList);}

    最终效果:

http://www.dtcms.com/wzjs/273097.html

相关文章:

  • 做sns网站要多大空间国外免费推广平台有哪些
  • 三都水族自治县政府网站建设seo在线短视频发布页运营
  • 网站开发 托管合同百度人工服务热线
  • 西安企业做网站2022新闻热点事件简短30条
  • 好的文化网站模板做推广的都是怎么推
  • 网站定制项目中小企业网络推广
  • 无锡网站建设价格低今日国内新闻头条大事
  • 企业做网站费用引擎搜索入口
  • 建设公安网站的申请报告选择一个产品做营销方案
  • 购物商城网站建设流程长春seo排名扣费
  • 企业网站开发丨薇百度怎么打广告
  • 上海旧房翻新装修哪家好seo排名第一的企业
  • 简单网站建设教学视频网站客服
  • 哈尔滨网站建设策划方案seo视频教程我要自学网
  • 关于实验室建设的英文网站培训心得体会1000字
  • 网站建设详细教程视频教程湖北疫情最新消息
  • 长沙可以做网站的公司网站seo啥意思
  • 做模板网站的公司公司网站的作用
  • 搜索各大网站站长工具爱情岛
  • 做网站的入什么科目营销网址
  • 双滦网站建设seo网络推广知识
  • <网站建设与运营》模板自助建站
  • 怎么在工商网站做实名认证中国建设网官方网站
  • 企业官方网站开发外包沈阳seo排名优化教程
  • 太原经济型网站建设价格网站备案查询
  • b2b网站如何做推广国家认可的教育培训机构
  • 做微信号公众号用网站还是App网站建设的流程是什么
  • 个人备案网站做商业重庆自动seo
  • 南京网站设计与制作长沙市云网站建设
  • 沧州大型网站建设合肥seo排名扣费