Caffeine
# Caffeine
作为单机服务的本地缓存,减少数据库的压力。它具有如下特征:
- 缓存过期策略
- 缓存淘汰策略(大小,lru)
- 缓存剔除失效监听器
# 集成SpringBoot
主要介绍两种方式,个人比较喜欢第一种,配置操作灵活。
# 方式一:将缓存作为bean对象
安装pom相关依赖:
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>
1
2
3
4
2
3
4
添加配置类config/CaffineCacheConfig.java,直接构造缓存的Bean对象。
@Configuration
public class CaffineCacheConfig {
@Bean
public Cache<String,Integer> countCache(){
return Caffeine.newBuilder().expireAfterWrite(100, TimeUnit.SECONDS)
.initialCapacity(100)
.maximumSize(1000)
.build();
}
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
在service当中,直接通过@Autowired注解拿到缓存对象。其中api如下:
- getIfPresent(key):根据key获取缓存中的value值
- invalidate(key):剔除缓存中key对应的条目
- asMap:返回Map对象,用于遍历
@Service
public class UserService {
@Autowired
private Cache<String,Integer> countCache;
public String getUserCount(String url) {
Integer count = countCache.getIfPresent(url);
count = count == null ? 1 : count + 1;
countCache.put(url, count);
String result = "";
for (Map.Entry<String, Integer> entry : countCache.asMap().entrySet()) {
result += entry.getKey() + ": " + String.valueOf(entry.getValue()) + "\n";
}
return result;
}
public void delKey(String url) {
countCache.invalidate(url);
}
public void refreshAll() {
countCache.invaludateAll();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 方式二:SpringCache注解
个人不是很喜欢~
安装pom依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
配置类中,需要注解CacheManage缓存管理器的Bean对象:
@Configuration
@EnableCaching
public class CacheConfig {
@Bean("caffeineCacheManager")
public CacheManager cacheManager() {
CaffeineCacheManager cacheManager = new CaffeineCacheManager();
cacheManager.setCaffeine(Caffeine.newBuilder()
.expireAfterAccess(60, TimeUnit.SECONDS)
.initialCapacity(100)
.maximumSize(1000));
return cacheManager;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
然后在service服务中,使用如下几种注解:
- @Cacheable(key="#id"):先根据方法的形参作为key查找缓存,如果有直接返回。否则执行方法,并将方法的返回值存入cache
- @CachePut(key = "#id"):向缓存插入数据
@Slf4j
@Service
@CacheConfig(cacheNames = "caffeineCacheManager")
public class UserInfoServiceImpl implements UserInfoService {
@Override
@CachePut(key = "#userInfo.id")
public void addUserInfo(UserInfo userInfo) {
userInfoMap.put(userInfo.getId(), userInfo);
}
@Override
@Cacheable(key = "#id")
public UserInfo getByName(Integer id) {
return userInfoMap.get(id);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 使用场景
# 场景一、登录接口防刷
需求:登录失败累计三次,则需要在五分钟之后才允许重试,防止恶意登录攻击数据库。
核心:使用Caffeine的expireAfterAccess方法,设置最后一次访问后的过期时间5分钟。
只要用户访问次数超过了三次,则进行拦截。仅当用户不再恶意访问5min后,缓存才会自动清理key,重新计数,向数据库请求验证。这里key可以设置为用户的IP。
public class LoginService {
private Cache<String, Integer> cache = Caffeine.newBuilder()
.expireAfterAccess(5, TimeUnit.MINUTES)
.maximumSize(1000).build();
public boolean login() {
String loginKey = requestUtils.getCurrentIp();
if(!loginChect(loginKey)) return false;
Integer count = cache.get(loginKey);
cache.put(loginKey, count + 1);
//查询数据库
return true;
}
public boolean loginChect(String loginKey) {
if (cache.getIfPresent(loginKey) > 3) {
return false;
}
return true;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
编辑 (opens new window)
上次更新: 2023/12/15, 15:49:57