本地缓存+分布式缓存(redis) 构建二级缓存
(1)解决redis 热key
(2)redis缓存io读写,毫秒级响应,本地缓存响应时间更短,亚秒级;对于响应要求更高的服务
数据读取
数据修改、删除(先删除本地,然后广播其他节点执行删除)
1.引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>19.0</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.3.17.RELEASE</version>
</dependency>
2.Guava相关类配置
(1)GuavaCacheConfig
package com.example.demo.config;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.guava.GuavaCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.concurrent.TimeUnit;
/**
* @author duanxiaoqiu
* @Date 2019-06-15 14:25
**/
@EnableConfigurationProperties(GuavaProperties.class)
@Configuration
@EnableCaching
public class GuavaCacheConfig {
@Autowired
private GuavaProperties guavaProperties;
@Bean
public CacheBuilder<Object,Object> cacheBuilder(){
long maximumSize = guavaProperties.getMaximumSize();
long expireAfterWrite = guavaProperties.getExpireAfterWriteDuration();
long expireAfterAccess = guavaProperties.getExpireAfterAccessDuration();
long refreshDuration = guavaProperties.getRefreshDuration();
if(maximumSize <= 0){
maximumSize = 1024;
}
if(expireAfterAccess <= 0){
expireAfterAccess = 3600;
}
if(expireAfterWrite <= 0){
expireAfterWrite = 3600;
}
if(refreshDuration <= 0){
refreshDuration = 1800;
}
return CacheBuilder.newBuilder().maximumSize(maximumSize)
.expireAfterWrite(expireAfterWrite,TimeUnit.SECONDS)
.refreshAfterWrite(refreshDuration,TimeUnit.SECONDS);
}
@Bean(name = "guavaCacheLoader")
public CacheLoader cacheLoader(){
return new GuavaCacheLoader();
}
@Bean
public CacheManager cacheManager(@Qualifier("cacheBuilder")CacheBuilder cacheBuilder,
@Qualifier("guavaCacheLoader")CacheLoader cacheLoader){
GuavaCacheManager cacheManager = new GuavaCacheManager();
cacheManager.setCacheBuilder(cacheBuilder);
cacheManager.setCacheLoader(cacheLoader);
return cacheManager;
}
}
(2)GuavaCacheLoader
package com.example.demo.config;
import com.google.common.cache.CacheLoader;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListenableFutureTask;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @author duanxiaoqiu
* @Date 2019-06-15 14:34
**/
public class GuavaCacheLoader extends CacheLoader<String,String> {
private final ExecutorService executorService = Executors.newFixedThreadPool(4);
@Override
public String load(String s) throws Exception {
if (s.equals("hello")) {
Thread.sleep(3000);
return "world";
} else if (s.equals("world")) {
Thread.sleep(5000);
return "hello";
}
return "no value";
}
@Override
public ListenableFuture<String> reload(String key, String oldValue) throws Exception {
ListenableFutureTask<String> task = ListenableFutureTask.create(new Callable<String>() {
@Override
public String call() throws Exception {
if (key.equals("hello")) {
return "nihao";
} else if (key.equals("world")) {
return "shijie";
}
return "no value";
}
});
executorService.submit(task);
return task;
}
}
(3)GuavaProperties
package com.example.demo.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
/**
* @author duanxiaoqiu
* @Date 2019-06-15 14:24
**/
@Configuration
@PropertySource("classpath:guava.properties")
@ConfigurationProperties(prefix = "guava.cache.config")
public class GuavaProperties {
private long maximumSize;
private long maximumWeight;
private long expireAfterWriteDuration;
private long expireAfterAccessDuration;
private long refreshDuration;
private int initialCapacity;
private int concurrencyLevel;
public long getMaximumSize() {
return maximumSize;
}
public void setMaximumSize(long maximumSize) {
this.maximumSize = maximumSize;
}
public long getMaximumWeight() {
return maximumWeight;
}
public void setMaximumWeight(long maximumWeight) {
this.maximumWeight = maximumWeight;
}
public long getExpireAfterWriteDuration() {
return expireAfterWriteDuration;
}
public void setExpireAfterWriteDuration(long expireAfterWriteDuration) {
this.expireAfterWriteDuration = expireAfterWriteDuration;
}
public long getExpireAfterAccessDuration() {
return expireAfterAccessDuration;
}
public void setExpireAfterAccessDuration(long expireAfterAccessDuration) {
this.expireAfterAccessDuration = expireAfterAccessDuration;
}
public long getRefreshDuration() {
return refreshDuration;
}
public void setRefreshDuration(long refreshDuration) {
this.refreshDuration = refreshDuration;
}
public int getInitialCapacity() {
return initialCapacity;
}
public void setInitialCapacity(int initialCapacity) {
this.initialCapacity = initialCapacity;
}
public int getConcurrencyLevel() {
return concurrencyLevel;
}
public void setConcurrencyLevel(int concurrencyLevel) {
this.concurrencyLevel = concurrencyLevel;
}
}
3.配置文件-- guava.properties
guava.cache.config.expire-after-write-duration=20
#更新间隔时长
guava.cache.config.refresh-duration=10
guava.cache.config.maximumSize=1024
4.使用
package com.example.demo.controller;
/**
* @author duanxiaoqiu
* @Date 2019-06-14 15:05
**/
import com.example.demo.dao.StudentDao;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Slf4j
@Controller
@RequestMapping("/")
public class TestController {
@Autowired
private StudentDao studentDao;
@Autowired
private CacheManager cacheManager;
@RequestMapping("/")
@ResponseBody
public String index() {
log.info(cacheManager.getCache("hello").getName());
log.info("++++");
return studentDao.getStuById(1).getName() + "hello world";
}
}
注:提示idea Spring Boot configuration not found in classpath
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
参考文章: