Caffeine本地缓存应用实践
1.1 概述
Caffeine是一种高性能的缓存库,内部使用ConcurrentHashMap实现,是基于Java 8的最佳缓存框架。基于 Google 的 Guava Cache,Caffeine 提供一个性能卓越的本地缓存实现 , 也是 SpringBoot 内置的本地缓存实现。
1.2 准备工作
在springboot工程中添加如下依赖
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
1.3 应用分析及实践
第一步:定义常量信息(非必须的,只是将几个固定值写到一个类中,方便获取和统一)
package cn.tedu.cache;
/**
* 此类定义常量信息
*/
public class CacheConstants {
/**
* 默认过期时间(配置类中我使用的时间单位是秒,所以这里如 3*60 为3分钟)
*/
public static final int DEFAULT_EXPIRES = 3 * 60;
public static final int EXPIRES_5_MIN = 5 * 60;
public static final int EXPIRES_10_MIN = 10 * 60;
public static final String CACHE1 = "CACHE1";
public static final String CACHE2 = "CACHE2";
}
第二步:创建枚举类(通过枚举定义一些固定实例),定义缓存相关信息
package cn.tedu.cache;
public enum CacheEnum {
/**
* 缓存1
*/
CACHE1(CacheConstants.CACHE1, CacheConstants.EXPIRES_5_MIN),
/**
* 缓存2
*/
CACHE2(CacheConstants.CACHE2, CacheConstants.EXPIRES_10_MIN),
;
/**
* 缓存名称
*/
private final String name;
/**
* 过期时间
*/
private final int expires;
/**
* 构造
*/
CacheEnum(String name, int expires) {
this.name = name;
this.expires = expires;
}
public String getName() {
return name;
}
public int getExpires() {
return expires;
}
}
第三步:定义缓存配置类
@EnableCaching //开启缓存
@Configuration
public class CacheConfig {
/**
* Caffeine配置说明:
* initialCapacity=[integer]: 初始的缓存空间大小
* maximumSize=[long]: 缓存的最大条数
* expireAfterWrite=[duration]: 最后一次写入后经过固定时间过期
* refreshAfterWrite=[duration]: 创建缓存或者最近一次更新缓存后经过固定的时间间隔,刷新缓存
*/
@Bean
public CacheManager cacheManager() {
SimpleCacheManager cacheManager = new SimpleCacheManager();
List<CaffeineCache> list = new ArrayList<>();
//循环添加枚举类中自定义的缓存
for (CacheEnum cacheEnum : CacheEnum.values()) {
list.add(new CaffeineCache(cacheEnum.getName(),
Caffeine.newBuilder()
.initialCapacity(50)
.maximumSize(1000) //缓存的最大条数
.expireAfterWrite(cacheEnum.getExpires(), TimeUnit.SECONDS)
.build()));
}
cacheManager.setCaches(list);
return cacheManager;
}
}
第四步:AOP方式启动缓存应用
@RestController
@Api(tags = "2.分类处理类")
public class CategoryController {
@Autowired
private CategoryMapper categoryMapper;
/**
* 查询分类列表
* @return
*/
@GetMapping("/category/list")
//添加缓存,value属性为添加到的缓存名字,sync表示异步
@Cacheable(value = CacheConstants.CACHE2,sync = true)
public List<Category> list(){
System.out.println("===获取数据===");
return categoryMapper.list();
}
/**
* 创建新分类
* @param category
*/
@PostMapping("/category/insert")
//清空缓存,value属性为添加到的缓存名字,allEntries = true表示清空所有
@CacheEvict(value = CacheConstants.CACHE2, allEntries = true)
public void doCreate(@RequestBody Category category){
categoryMapper.insert(category);
}
/**
* 基于id删除分类
* @param id
*/
@DeleteMapping("/category/delete/{id}")
@CacheEvict(value = CacheConstants.CACHE2, allEntries = true)
public void doDeleteById(@PathVariable("id") Integer id){
categoryMapper.deleteById(id);
}
}
第五步:启动服务,访问分类数据,检测缓存应用。
拦截器
2.1 背景
项目增加新的需求,要求系统登陆操作要有时间限制。
2.2 原理应用分析
拦截器 (Interceptor) 是一种动态拦截方法调用的机制,在SpringMVC中动态拦截控制器方法的执行 , 可以在目标方法执行之前,先进行业务检测,满足条件则放行,不满足条件则进行拦截,拦截器原理分析如下图所示:
2.3 最终解决方案实现
第一步:拦截器定义,关键代码如下:
/**
* Spring MVC中拦截器
* @author Administrator
*/
public class TimeInterceptor implements HandlerInterceptor {
/**
* preHandle在控制层目标方法执行之前执行
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("preHandler()");
//获取java中的日历对象
Calendar c = Calendar.getInstance();
c.set(Calendar.HOUR_OF_DAY, 6);
c.set(Calendar.MINUTE, 0);
c.set(Calendar.SECOND, 0);
long start = c.getTimeInMillis();
c.set(Calendar.HOUR_OF_DAY,14);
long end = c.getTimeInMillis();
long cTime = System.currentTimeMillis();
if(cTime<start||cTime>end)
throw new RuntimeException("不在访问时间之内");
return true;
}
}
第二步:拦截器配置,关键代码如下 :
@Configuration
public class SpringWebConfig implements WebMvcConfigurer {
//配置spring mvc 拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new TimeInterceptor()).addPathPatterns("/user/login");
}
}