栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Springboot整合缓存组件

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Springboot整合缓存组件

Springboot整合缓存组件

spring-boot-cache支持如下缓存

Generic、JCache (JSR-107)、EhCache 2.x、Hazelcast、Infinispan、Redis、Guava、Simple

一、快速入门 1、添加依赖

	org.springframework.boot
	spring-boot-starter-cache

2、启动类添加注解
  • @EnableCaching 用于缓存配置类或者启动类上
3、添加配置

spring.cache.type指定缓存组件,详细的见下面的

spring:
  cache:
    type: XXX  ## 设置缓存类型为caffeine
4、业务类使用注解以及使用
  • @CacheConfig 单个缓存管理配置,添加在需要缓存类上
    • cacheNames或value 指定缓存名称
    • cacheManager 指定的缓存换利器
    • cacheResolver 指定的缓存解析器
  • @Cacheable 用于查询方法上,表示缓存查询的结果
    • key= “#root.methodName” 指定缓存key的表达式,一般采用spEL表达式
    • condition = “#id>2” 缓存的条件,例如id>2
    • unless = “#a0==null” 不缓存的条件,例如第一个参数为null
    • keyGenerator 指定缓存的key生成器
    • sync 默认为false,实际调用方法获取数据时是否要保持同步
  • @CachePut 用于更新方法上,表示更新缓存
    • key = “#student.id”
    • condition 满足条件时更新缓存,支持SpEL表达式
    • unless 满足条件时不更新缓存,支持spEL表达式
  • @CacheEvict 用于删除方法上,表示删除缓存
    • key = “#id” 指定缓存的key
    • allEntries = true 默认为false,是否要清除所有缓存数据
    • value或cacheNames 指定缓存名称
    • condition 满足条件时删除缓存,支持SpEL表达式
    • beforeInvocation 默认为false,调用方法之前或之后清除缓存
  • @Caching 用在一个方法上多种注解
    • cacheable 对应的是@Cacheable
    • put 对应的是配置@CachePut
    • evict 对应的是@CacheEvict
@CacheConfig(cacheNames = "student")
public class StudentService {
    
    //表示将sno作为key,添加key
	@Cacheable(key= "#root.methodName",condition = "#id>2",unless = "#a0==null")
	public Student queryStudentBySno(Integer id){
	    //添加缓存
	}
	
    //#p0.sno表示将student的sno作为key,更新key
	@CachePut(key = "#student.id")
	public Student update(Student student){
	    //更新缓存
	}
	
    //将sno作为key,移除缓存中的key
	@CacheEvict(key = "#id", allEntries = true)
	public void deleteStudentBySno(Integer id){
	    //删除缓存
	}
}
二、使用Caffine缓存组件(基于内存缓存) 1、添加依赖

    com.github.ben-manes.caffeine
    caffeine
    2.6.0

2、修改配置
  • maximumWeight=[long]: 缓存的最大权重
  • expireAfterAccess=[duration]: 最后一次写入或访问后经过固定时间过期
  • expireAfterWrite=[duration]: 最后一次写入后经过固定时间过期
  • refreshAfterWrite=[duration]: 创建缓存或者最近一次更新缓存后经过固定的时间间隔,刷新缓存
  • weakKeys: 打开key的弱引用
  • softValues:打开value的软引用
  • recordStats:开发统计功能
  • initialCapacity=[integer]: 初始的缓存空间大小
spring:
  cache:
    type: caffeine  ## 设置缓存类型为caffeine
    cache-names:
    - getPersonById  # 指定缓存名称
    - name2
    caffeine:
      spec: maximumSize=500,expireAfterWrite=5s   # 缓存配置
3、Caffine本身API灵活运用 (1)定义缓存枚举
@Getter
@NoArgsConstructor
@AllArgsConstructor
public enum Caches{
    getPersonById(5), //有效期5秒
    getSomething, //缺省10秒
    getOtherthing(300, 1000), //5分钟,最大容量1000
    ;
    //缺省情况
    private int maxSize=50000;    //最大數量
    private int ttl=10;        //过期时间(秒)

    Caches(int ttl) {
        this.ttl = ttl;
    }
}
(2)自定义缓存配置类
@Configuration
@EnableCaching
public class CacheConfig {

    public static final int DEFAULT_MAXSIZE = 50000;
    public static final int DEFAULT_TTL = 10;

    @Bean
    @Primary
    public CacheManager caffeineCacheManager() {
        SimpleCacheManager cacheManager = new SimpleCacheManager();
        ArrayList caches = new ArrayList();
        //从缓存枚举中获取到所有情况的缓存
        for(Caches c : Caches.values()){
            caches.add(new CaffeineCache(c.name(), 
                Caffeine.newBuilder().recordStats()
                .expireAfterWrite(c.getTtl(), TimeUnit.SECONDS)
                .maximumSize(c.getMaxSize())
                .build())
            );
        }
        cacheManager.setCaches(caches);
        return cacheManager;
    }
    
    @Bean
    public CacheLoader cacheLoader() {
        CacheLoader cacheLoader = new CacheLoader() {
            @Override
            public Object load(Object key) throws Exception {
                return null;
            }
            // 重写这个方法将oldValue值返回回去,进而刷新缓存
            @Override
            public Object reload(Object key, Object oldValue) throws Exception {
                return oldValue;
            }
        };
        return cacheLoader;
    }
}   
(3)使用API操作
//缓存加载器
LoadingCache loadingCache = Caffeine.newBuilder()
        .maximumSize(10_000)
        .expireAfterWrite(10, TimeUnit.MINUTES)
        .build(key -> createExpensiveGraph(key));
//查询数据先查询缓存
private Object createExpensiveGraph(String key) {
    Object graph = null;
    //先查询缓存是否存在,这里也可以做成函数式编程
    graph = manualCache.getIfPresent(key);
    if(null != graph){
        return  graph;
    }
    return personService.findOne1();
}
//关于Caffine缓存的增删改查使用
public Object testManual(Person person) {
    String key = "name1";
    Object graph = null;
    // 根据key查询一个缓存,如果没有返回NULL
    graph = manualCache.getIfPresent(key);
    // 根据Key查询一个缓存,如果没有调用createExpensiveGraph方法,并将返回值保存到缓存。
    // 如果该方法返回Null则manualCache.get返回null,如果该方法抛出异常则manualCache.get抛出异常
    graph = manualCache.get(key, k -> createExpensiveGraph(k));
    // 将一个值放入缓存,如果以前有值就覆盖以前的值
    manualCache.put(key, graph);
    // 删除一个缓存
    manualCache.invalidate(key);
    ConcurrentMap map = manualCache.asMap();
    System.out.println(map.toString());
    return graph;
}
//异步缓存
AsyncLoadingCache asyncLoadingCache = Caffeine.newBuilder()
        .maximumSize(10_000)
        .expireAfterWrite(10, TimeUnit.MINUTES)
        .buildAsync(key -> createExpensiveGraph(key));

private CompletableFuture createExpensiveGraphAsync(
    			String key, Executor executor) {
    CompletableFuture objectCompletableFuture = new CompletableFuture<>();
    return objectCompletableFuture;
}
 
三、使用Redis作为缓存组件 
1、添加依赖 

    org.springframework.boot
    spring-boot-starter-data-redis

2、添加配置
spring: 
  redis:
    database: 0 # Redis数据库索引(默认为0)
    host: localhost  # Redis服务器地址
    port: 6379  # Redis服务器连接端口
    pool:
      max-active: 8  # 连接池最大连接数(使用负值表示没有限制)
      max-wait: -1 # 连接池最大阻塞等待时间(使用负值表示没有限制)
      max-idle: 8 # 连接池中的最大空闲连接
      min-idle: 0 # 连接池中的最小空闲连接
    timeout: 0  # 连接超时时间(毫秒)
3、添加配置类

这里定义的缓存key生成策略,缓存管理器,模板类都可以使用到@CacheConfig注解中

@Configuration
public class RedisConfig extends CachingConfigurerSupport {
	// 自定义缓存key生成策略
	@Bean
	public KeyGenerator keyGenerator() {
		return new KeyGenerator() {
			@Override
			public Object generate(Object target,  Method method, Object... params) {
				StringBuffer sb = new StringBuffer();
				sb.append(target.getClass().getName());
				sb.append(method.getName());
				for (Object obj : params) {
					sb.append(obj.toString());
				}
				return sb.toString();
			}
		};
	}
    
	// 缓存管理器
	@Bean
	public CacheManager cacheManager( RedisTemplate redisTemplate) {
		RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);
		// 设置缓存过期时间
		cacheManager.setDefaultExpiration(10000);
		return cacheManager;
	}
    //redis模板类
	@Bean
	public RedisTemplate redisTemplate(RedisConnectionFactory factory) {
		StringRedisTemplate template = new StringRedisTemplate(factory);
		setSerializer(template);// 设置序列化工具
		template.afterPropertiesSet();
		return template;
	}
    //设置序列化和发序列化
	private void setSerializer(StringRedisTemplate template) {
		@SuppressWarnings({ "rawtypes", "unchecked" })
		Jackson2JsonRedisSerializer jackson2JsonRedisSerializer =
            		new Jackson2JsonRedisSerializer(Object.class);
		ObjectMapper om = new ObjectMapper();
		om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
		om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
		jackson2JsonRedisSerializer.setObjectMapper(om);
		template.setValueSerializer(jackson2JsonRedisSerializer);
	}
}
4、使用Redis的API(基于Jedis客户端实现)

基于StringRedisTemplate即字符串序列化的可用方法

//Redis的示例以及对所有key操作
StringRedisTemplate redisTemplate;

redisTemplate.delete(key);
redisTemplate.delete(keys);
redisTemplate.hasKey(key);
redisTemplate.expire(key,expireTime, TimeUnit.SECONDS);
redisTemplate.keys(key);
//Hash类型数据操作
HashOperations hashOpt = redisTemplate.opsForHash();
hashOpt.get(hashKey, hashItem);
hashOpt.put(hashKey, hashItem, value);
hashOpt.entries(hashKey);
hashOpt.values(hashkey);
hashOpt.delete(hashKey, hashItem);
hashOpt.putAll(key,  var2);
//Set类型操作
SetOperations setOpt = redisTemplate.opsForSet();
setOpt.add(key,value);
setOpt.remove(key,value);
setOpt.members(key);
//Zset类型操作   
Map scoreMap = Maps.newHashMapWithExpectedSize(1);
scoreMap.put(val,score);
zsetAddAll(key,scoreMap);
reverseRangeWithScores(key,start, end);
reverseRangeWithScores(key,start, end);  
remove(key,value);   
incrementScore(key, item, score);
size(key);  
rank(key, item);
//其他略

四、使用JetCache作为缓存组件
  • JetCache作为代理Redis或者Caffine缓存组件
  • JetCache可以设置一级缓存和二级缓存
1、添加依赖

    com.alicp.jetcache
	jetcache-starter-redis-lettuce
	2.6.0.M1



    org.springframework.boot
	spring-boot-starter-data-redis



	org.apache.commons
	commons-pool2

2、添加配置
jetcache:  
    statIntervalMinutes: 15  
    areaInCacheName: false  
    # 一级本地缓存
    local:    
          default:      
                type: linkedhashmap      
                keyConvertor: fastjson    
         otherCacheName:      
               type: linkedhashmap      
               keyConverter: fastjson  
    # 二级远程缓存
    remote:    
         default:      
               type: redis.lettuce     
               keyConvertor: fastjson      
               valueEncoder: java      
               valueDecoder: java      
               poolConfig:        
                      minIdle: 5        
                      maxIdle: 20        
                      maxTotal: 50      
               uri:
                    - redis://password@192.168.14.231:6379/0  #redis://密码@IP:端口/库
                    - redis://password@192.168.14.232:6379/0
                    - redis://password@192.168.14.233:6379/0
              readFrom: masterPreferred #master优先
2、添加类配置
  • @EnableMethodCache 开启方法级缓存
  • @EnableCreateCacheAnnotation 开启创建缓存注解
@SpringBootApplication
@EnableMethodCache(basePackages = { "com.xxxx" })
@EnableCreateCacheAnnotation
public class Application {
     SpringApplication.run(Application.class,args);
}
3、在控制层开启缓存
@RestController
public class UserController {

    // 定义一个是String类型的远程缓存
     @CreateCache(name ="i5xforyou.username", expire = 120, cacheType = CacheType.REMOTE)
     private Cache userNameCache;
     
    // 定义一个是User对象的二级缓存(本地+远程)
    @CreateCache(name ="i5xforyou.user", localExpire = 60, localLimit = 100, expire = 120, cacheType = CacheType.BOTH)
    private Cache userCache;
    
    @GetMapping(value = "/getUser")
    public String getUserInfo() {
        // 远程缓存
        userNameCache.put("123", "userName");
        System.out.println("userNameCache : " + userNameCache.get("123"));

        User user = new User();
        user.setUserName("user.userName");
        //远程二级缓存
        userCache.put("1234", user);
        System.out.println("userCache: " + userCache.get("1234").geUserName());
        return "";
    }
}
4、在业务接口上开启缓存
public interface UserService {

    @Cached(name="userCache-", key="#userId", expire = 3600)
    User getUserById(long userId);

    @CacheUpdate(name="userCache-", key="#user.userId", value="#user")
    void updateUser(User user);

    @CacheInvalidate(name="userCache-", key="#userId")
    void deleteUser(long userId);
    
    @Cached(expire = 3600, cacheType = CacheType.REMOTE)
    @CacheRefresh(refresh = 1800, stopRefreshAfterLastAccess = 3600, timeUnit = TimeUnit.SECONDS)
    @CachePenetrationProtect
    BigDecimal summaryOfToday(long catagoryId);
}
5、使用缓存池以及相关API
## JedisPool创建对象池
GenericObjectPoolConfig pc = new GenericObjectPoolConfig();
    pc.setMinIdle(2);
    pc.setMaxIdle(10);
    pc.setMaxTotal(10);
JedisPool pool = new JedisPool(pc, "localhost", 6379);

## 创建userCache
Cache userCache = RedisCacheBuilder.createRedisCacheBuilder()
                .keyConvertor(FastjsonKeyConvertor.INSTANCE)
                .valueEncoder(JavaValueEncoder.INSTANCE)
                .valueDecoder(JavaValueDecoder.INSTANCE)
                .jedisPool(pool)
                .keyPrefix("userCache-")
                .expireAfterWrite(200, TimeUnit.SECONDS)
                .buildCache();
                
                
CacheGetResult r = cache.GET(userId);
CompletionStage future = r.future();
future.thenRun(() -> {
    if(r.isSuccess()){
        System.out.println(r.getValue());
    }
})

## 使用分布式锁
cache.tryLockAndRun("key", 60, TimeUnit.SECONDS, () -> heavyDatabaseOperation());

## 数据预加载
@CreateCache
@CacheRefresh(timeUnit = TimeUnit.MINUTES, refresh = 60, stopRefreshAfterLastAccess = 100)
@CachePenetrationProtect
private Cache orderSumCache;

@PostConstruct
public void init(){
    orderSumCache.config().setLoader(this::loadOrderSumFromDatabase);
}
五、使用EhCache

springboot没有对ehcache进行整合,只能使用原生的方式

1、添加依赖

	net.sf.ehcache
	ehcache

2、添加ehcache.xml配置文件
  • diskStore:为缓存路径,ehcache分为内存和磁盘两级,此属性定义磁盘的缓存位置。
  • defaultCache:默认缓存策略,当ehcache找不到定义的缓存时,则使用这个缓存策略。只能定义一个。
  • name:缓存名称。
  • maxElementsInMemory:缓存最大数目
  • maxElementsOnDisk:硬盘最大缓存个数。
  • eternal:对象是否永久有效,一但设置了,timeout将不起作用。
  • overflowToDisk:是否保存到磁盘,当系统宕机时
  • timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
  • timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。
  • diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
  • diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
  • diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
  • memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
  • clearOnFlush:内存数量最大时是否清除。


	
    
	
	

3、添加配置
spring: 
  cache:
    ehcache:
      config: 'classpath:ehcache.xml'
4、Ehcache的缓存使用
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.MOCK)
public class TestCache {
  @Resource
  private CacheManager cacheManager;

  @Test
  public void cacheTest() {
    // 显示所有的Cache空间
    System.out.println(StringUtils.join(cacheManager.getCacheNames(), ","));
    Cache cache = cacheManager.getCache("userCache");
    cache.put("key", "123");
    System.out.println("缓存成功");
    String res = cache.get("key", String.class);
    System.out.println(res);
  }
}
CacheManager转换
/ 获取EhCache的管理器
    org.springframework.cache.ehcache.EhCacheCacheManager cacheCacheManager = (EhCacheCacheManager) cacheManager;
    net.sf.ehcache.CacheManager ehCacheManager = cacheCacheManager.getCacheManager();
    net.sf.ehcache.Cache ehCache = ehCacheManager.getCache("userCache");
六、使用Memcache缓存组件

Springboot没有对Memcache做整合

1、添加依赖

  net.spy
  spymemcached
  2.12.3

2、添加配置
memcache:
	ip: 192.168.0.161
	port: 11211
3、添加配置类
@Data
@Component
@ConfigurationProperties(prefix = "memcache")
public class MemcacheSource {
    private String ip;
    private int port;
}
4、初始化Memcache对象
@Component
public class MemcachedRunner implements CommandLineRunner {
    protected Logger logger =  LoggerFactory.getLogger(this.getClass());

    @Resource
    private  MemcacheSource memcacheSource;

    private MemcachedClient client = null;

    @Override
    public void run(String... args) throws Exception {
        try {
            client = new MemcachedClient(
                new InetSocketAddress(
                    memcacheSource.getIp(),
                    memcacheSource.getPort()));
        } catch (IOException e) {
            logger.error("inint MemcachedClient failed ",e);
        }
    }

    public MemcachedClient getClient() {
        return client;
    }

}
5、使用Memcache
@RunWith(SpringRunner.class)
@SpringBootTest
public class RepositoryTests {

  @Resource
    private MemcachedRunner memcachedRunner;

  @Test
  public void testSetGet()  {
    MemcachedClient memcachedClient = memcachedRunner.getClient();
    //测试添加缓存
    memcachedClient.set("testkey",1000,"666666");
	//测试获取缓存
    String test= memcachedClient.get("testkey").toString();
    System.out.println(test);
  }

}
转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号