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

网站首页默认的文件名一般为淘宝客建设网站

网站首页默认的文件名一般为,淘宝客建设网站,营销型企业网站优点,网页设计软件下载网站整体思路: 创建EnableLocalCache注解,用于选择是否开启本地缓存创建LocalCache注解和LocalCacheEvict注解用于缓存的构建、过期时间和清除切面实现缓存的获取、写入和清除SpEL表达式的支持缓存配置类,用于创建Bean对象开启定时任务清除过期的…

整体思路:

  1. 创建@EnableLocalCache注解,用于选择是否开启本地缓存
  2. 创建@LocalCache注解和@LocalCacheEvict注解用于缓存的构建、过期时间和清除
  3. 切面实现缓存的获取、写入和清除
  4. SpEL表达式的支持
  5. 缓存配置类,用于创建Bean对象
  6. 开启定时任务清除过期的缓存,支持自定义任务参数

项目示例Gitee地址: Java实现本地缓存demo

效果展示:


代码实现:

 1.引入基本依赖:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><version>2.7.10</version>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId><version>2.7.10</version>
</dependency>
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.22</version>
</dependency>

2.创建注解:

2.1 @EnableLocalCache 开启缓存,@Import(LocalCacheConfig.class)导入缓存配置类
package com.gooluke.localcache.annotation;import com.gooluke.localcache.config.LocalCacheConfig;
import org.springframework.context.annotation.Import;import java.lang.annotation.*;/*** @author gooluke* 开启本地缓存*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(LocalCacheConfig.class)
@Documented
public @interface EnableLocalCache {
}
2.2 @LocalCache 使用缓存
package com.gooluke.localcache.annotation;import java.lang.annotation.*;
import java.util.concurrent.TimeUnit;/*** @author gooluke* 本地缓存注解*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LocalCache {/*** 缓存key* 支持SpEL表达式*/String key() default "";/*** 缓存过期时间 0-表示永不过期*/long timeout() default 0;/*** 缓存过期时间单位*/TimeUnit timeUnit() default TimeUnit.SECONDS;}
2.3 @LocalCacheEvict 清除缓存
package com.gooluke.localcache.annotation;import java.lang.annotation.*;/*** @author gooluke* 删除缓存注解*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LocalCacheEvict {/*** 要清除缓存的key* 支持SpEL表达式*/String key();}

3.切面类

3.1 LocalCacheAspect 缓存切面类
package com.gooluke.localcache.aop;import com.gooluke.localcache.annotation.LocalCache;
import com.gooluke.localcache.cache.LocalCacheManager;
import com.gooluke.localcache.utils.SpELUtil;
import lombok.AllArgsConstructor;
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;@Aspect
@AllArgsConstructor
@Slf4j
public class LocalCacheAspect {private final LocalCacheManager cacheManager;@Around("@annotation(localCache)")public Object cacheMethod(ProceedingJoinPoint joinPoint, LocalCache localCache) throws Throwable {// 获取方法签名MethodSignature signature = (MethodSignature) joinPoint.getSignature();// 获取方法的返回类型Class<?> returnType = signature.getReturnType();// 获取方法的全路径限定名(包括包名、类名和方法名)String methodName = signature.getMethod().toString();// 构建缓存键String cacheKey = (localCache.key() != null && !localCache.key().isEmpty()) ? SpELUtil.parseSpEl(localCache.key(), joinPoint) : methodName;// 尝试从缓存中获取数据Object cachedValue = cacheManager.getCache(cacheKey);if (cachedValue != null) {// 如果缓存中有数据,则直接返回return returnType.cast(cachedValue); // 强制转换为方法的返回类型} else {long timeout = localCache.timeout();// 如果没有缓存,则执行目标方法Object proceed = joinPoint.proceed();// 将结果放入缓存if (timeout == 0) {cacheManager.addCache(cacheKey, proceed);} else {cacheManager.addCache(cacheKey, proceed, timeout, localCache.timeUnit());}return proceed;}}
}
3.2 LocalCacheEvictAspect 清除缓存的切面类
package com.gooluke.localcache.aop;import com.gooluke.localcache.annotation.LocalCacheEvict;
import com.gooluke.localcache.cache.LocalCacheManager;
import com.gooluke.localcache.utils.SpELUtil;
import lombok.AllArgsConstructor;
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;@Aspect
@AllArgsConstructor
@Slf4j
public class LocalCacheEvictAspect {private final LocalCacheManager cacheManager;@Around("@annotation(localCacheEvict)")public Object cacheMethod(ProceedingJoinPoint joinPoint, LocalCacheEvict localCacheEvict) throws Throwable {// 获取方法签名MethodSignature signature = (MethodSignature) joinPoint.getSignature();// 获取方法的全路径限定名(包括包名、类名和方法名)String methodName = signature.getMethod().toString();// 构建缓存键String cacheKey = (localCacheEvict.key() != null && !localCacheEvict.key().isEmpty()) ? SpELUtil.parseSpEl(localCacheEvict.key(), joinPoint) : methodName;//删除缓存cacheManager.deleteCache(cacheKey);return joinPoint.proceed();}
}

4.SpEL工具类

package com.gooluke.localcache.utils;import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;import java.lang.reflect.Method;
import java.util.Optional;/*** @author gooluke* datetime 2024/12/5 19:19*/
public class SpELUtil {/*** 用于SpEL表达式解析*/private static final ExpressionParser parser = new SpelExpressionParser();/*** 解析、获取参数名*/private static final DefaultParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();public static String parseSpEl(String spEl, ProceedingJoinPoint joinPoint) {if (spEl == null || spEl.isEmpty()) {return "";}MethodSignature signature = (MethodSignature) joinPoint.getSignature();Method method = signature.getMethod();Object[] args = joinPoint.getArgs();//这里是因为args里没有参数名,只有值,所以只能从DefaultParameterNameDiscoverer去获取参数名String[] params = Optional.ofNullable(parameterNameDiscoverer.getParameterNames(method)).orElse(new String[]{});EvaluationContext context = new StandardEvaluationContext();//el解析需要的上下文对象for (int i = 0; i < params.length; i++) {context.setVariable(params[i], args[i]);//所有参数都作为原材料扔进去-基于参数名称context.setVariable("p" + i, args[i]);//所有参数都作为原材料扔进去-基于参数位置}Expression expression = parser.parseExpression(spEl);return expression.getValue(context, String.class);}public static String getMethodKey(Method method) {return method.getDeclaringClass() + "#" + method.getName();}
}

5.缓存管理类LocalCacheManager&&缓存对象LocalCacheItem

5.1 LocalCacheManager 缓存管理器
package com.gooluke.localcache.cache;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;public class LocalCacheManager {private static final Logger log = LoggerFactory.getLogger(LocalCacheManager.class);private final Map<String, LocalCacheItem<Object>> cacheMap = new ConcurrentHashMap<>();/*** 添加不过期缓存*/public void addCache(String name, Object object) {addCache(name, object, 0, null);}public void addCache(String name, Object object, long timeout, TimeUnit timeUnit) {if (name == null) {return;}cacheMap.put(name, new LocalCacheItem<>(object, timeout, timeUnit));}public void deleteCache(String name) {cacheMap.remove(name);}public Object getCache(String name) {if (name == null) {return null;}LocalCacheItem<Object> cache = cacheMap.getOrDefault(name, null);if (cache != null) {if (cache.isExpired()) {deleteCache(name);return null;} else {return cache.getValue();}}return null;}/*** 清理所有已过期的缓存项*/public void cleanupExpired() {try {log.info("清除前总缓存数量:" + cacheMap.size());// 移除过期的缓存项cacheMap.entrySet().removeIf(entry -> entry.getValue().isExpired());log.info("清除过期缓存后总缓存数量:" + cacheMap.size());} catch (Exception e) {log.error("定时清除本地缓存异常:", e);}}}
5.2 LocalCacheItem 本地缓存对象
package com.gooluke.localcache.cache;import lombok.Getter;import java.util.concurrent.TimeUnit;public class LocalCacheItem<T> {@Getterprivate final T value;private final long expiryTime; // 过期时间戳public LocalCacheItem(T value, long timeout, TimeUnit timeUnit) {this.value = value;this.expiryTime = timeout == 0 ? 0 : System.currentTimeMillis() + timeUnit.toMillis(timeout);}public boolean isExpired() {return expiryTime != 0 && System.currentTimeMillis() > expiryTime;}
}

6.缓存配置类LocalCacheConfig

package com.gooluke.localcache.config;import com.gooluke.localcache.aop.LocalCacheAspect;
import com.gooluke.localcache.aop.LocalCacheEvictAspect;
import com.gooluke.localcache.cache.LocalCacheManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.annotation.Bean;import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;public class LocalCacheConfig implements ApplicationRunner, DisposableBean {private static final Logger log = LoggerFactory.getLogger(LocalCacheConfig.class);private final LocalCacheManager localCacheManager = new LocalCacheManager();private final ScheduledExecutorService CACHE_CLEANUP_SCHEDULER = Executors.newScheduledThreadPool(1);@Value("${cache.cleanup.initialDelay:0}")private long initialDelay;@Value("${cache.cleanup.period:60}")private long period;@Beanpublic LocalCacheAspect localCacheAspect() {return new LocalCacheAspect(this.localCacheManager);}@Beanpublic LocalCacheEvictAspect localCacheEvictAspect() {return new LocalCacheEvictAspect(this.localCacheManager);}@Overridepublic void run(ApplicationArguments args) throws Exception {log.info("CACHE_CLEANUP_SCHEDULER task initialDelay:{},period:{}", initialDelay, period);CACHE_CLEANUP_SCHEDULER.scheduleAtFixedRate(localCacheManager::cleanupExpired, initialDelay, period, TimeUnit.SECONDS);}@Overridepublic void destroy() throws Exception {log.info("关闭CACHE_CLEANUP_SCHEDULER");CACHE_CLEANUP_SCHEDULER.shutdown();}
}

7.主启动类开启本地缓存

package com.gooluke.localcache;import com.gooluke.localcache.annotation.EnableLocalCache;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;/*** @author gooluke*/
@SpringBootApplication
@EnableLocalCache//开启本地缓存
public class LocalCacheDemoApplication {public static void main(String[] args) {SpringApplication.run(LocalCacheDemoApplication.class, args);}}

8.支持配置定时清除过期缓存的任务参数,不配置默认延迟0s,间隔60s

#延迟启动
cache.cleanup.initialDelay=10
#缓存清理间隔
cache.cleanup.period=30

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

相关文章:

  • 做信息分类网站难吗关闭开发者模式
  • 陕西交通建设集团蓝商公司网站wordpress新建文章页修改图片样式
  • 制作一个自适应网站源码wordpress安装到虚机
  • 工信部外国网站备案seo资料
  • 广州市外贸网站建设企业做网站前台用什么
  • 建设网站和网页有啥区别关键词排名优化易下拉技巧
  • 扁平化风格网站模板dede 网站地图样式
  • 制作网站的软件什么好用跑腿小程序开发
  • 建设网站要多少页面wordpress theme 免费
  • 三线建设网站wordpress点击量
  • 长沙网站推广智投未来北京最好设计公司
  • 普通营业执照有做网站条件吗wordpress首页添加js
  • 上海网站优化推广网站建设后台系统有哪些
  • 门户做网站公司网站费用构成需要多少钱
  • 搜狗网站推广做网站怎样盈利
  • 响应式网站和传统网站异同wordpress 搬家教程
  • 下载了网站源码营销型科技网站
  • 怎样解析网站域名网络营销公司排名
  • 网站cname京东网站建设流程和结构图
  • python做网站源码浏阳做网站
  • 网站cms在线识别建立网站的主要方式
  • ae做网站导航我的世界电影怎么做的视频网站
  • 如何跟客户销售做网站唐山手机网站建设
  • vue做移动端网站与pc端有什么区别专做水果的网站
  • 网站怎么做的支付宝企业为什么要管理
  • 注册公司一年需要多少费用seo搜索优化公司排名
  • 哪些网站是专做女性护肤品中国500强企业名称
  • 东方建设官方网站网站的建设与运营
  • 太原网站推广服务互联网兼职做网站维护
  • 怎么做网站门户企业网站需要响应式