• 缓存

    • 服务器自身(内存)的缓存

      • 利用java程序中的变量

        • 简单
        • 集群环境中多个实例无法共享同步
    • 缓存服务器(一般支持集群、分布式)
      • Redis
      • Memcached
  • Spring中使用注解使用缓存
    • 启动类或者配置类

      • 使用@EnableCaching,必须使用,否则后续注解虽然不报错,但没有使用缓存
      • 可以放一个@Bean,用来注入CacheManager
@EnableCaching
@EnableScheduling
@Configuration
public class CacheConfig {

    @Bean
    @Primary
    public CacheManager cacheManager() {
        return new ConcurrentMapCacheManager("assets");
    }

}
* 使用注解标识方法()
    * @Cacheable,通常用在get方法上
    * @CachePut:运行后会更新/新建缓存中的值,通常用在update方法上
    * @CacheEvict:运行后会删掉缓存中的值,通常用在delete方法上
* 使用注解标识类(方法上就不用标识了)
    * @CacheConfig:相当于该类下所有的方法的cacheNames都是其中指定的字符串?
* 参数
    * 标识缓存项,都是用注解中的cacheNames参数和key参数组合起来的:**缓存的key是cacheNames::key**
        * cacheNames可以是一个字符串数组,可以对应多个缓存的key,每个方法都需要指定cacheNames参数
        * key
            * 通常用SpringEL表达式。
            * 以\#开头,内部以.进行分级分隔。
            * **默认按照方法的参数自动生成**
            * 可以通过keyGenerator参数自定义生成方式
            * 有时key可以省略,key有默认的机制。如果方法只有一个参数,那么就会用cacheNames和参数值组合成key;如果有多个参数的时候,就会把多个参数组合起来再组合成key。**所有要看情况,key有时可以省略,有时不可以。**
    * condition可以指定一个条件,用于执行方法前判断是否使用注解的功能
    * unless用于执行方法后,用返回值?判断是否使用注解提供的功能
    * cacheManager、CacheResolver、keyGenerator
    * @CacheEvict多了两个参数
        * allEntries:值为true则不管key,清除cacheName下所有key的缓存
        * beforeInvocation:值为true,执行方法前清除,默认是执行方法后清除
* 设置缓存过期
    * 可以和Scheduled Tasks结合,使用CacheEvict注解定时清除缓存
    * 某些缓存服务如Redis,可以通过application.yml配置一个全局的过期时间(默认不过期)
  • 使用Redis

    • 在maven或者gradle中加入依赖
    • 在application.yml中加入配置
    • 可以通过使用RedisTemplate(RabbitMQ中有类似的概念用来发数据到队列)单独设置一些过期时间等
    • 有可能的坑
      • application.yml中其实可以配置key前缀、是否使用key前缀。如果打开了这两个开关,那么有可能导致代码中的cacheNames参数失效,如果两个方法的key相同,那么会导致缓存的key相同导致混乱。根本原因是spring把cacheNames参数也当成了application.yml中所谓的key,所以这两个参数一般不要配
    • 使用
      • 需要在build.gradle中添加依赖:compile('org.springframework.boot:spring-boot-starter-data-redis'),然后就可以使用RedisTemplate<String, XXX>类了
      • application.properties文件中的配置
      • 配置类(其实这一个就够了)
        • 注入生成的redisSetRepository可以直接用来进行redis操作,比如redisRepository.put
@Configuration
public class RedisConfig {

    @Autowired
    private RedisConnectionFactory redisConnectionFactory;

    @Value("${oee.cache.ttl.hours:24}")
    private long timeout;

    @Bean
    public RedisRepository redisRepository()
    {
        return new RedisRepository(cacheEntryRedisTemplate(), timeout, TimeUnit.HOURS);
    }

    @Bean
    public RedisSetRepository redisSetRepository()
    {
        return new RedisSetRepository(stringRedisTemplate());
    }

    private RedisTemplate<String, CacheEntry> cacheEntryRedisTemplate()
    {
        StringRedisSerializer stringSerializer = new StringRedisSerializer(StandardCharsets.UTF_8);
        Jackson2JsonRedisSerializer<CacheEntry> contentSerializer = new Jackson2JsonRedisSerializer<>(CacheEntry.class);
        RedisTemplate<String, CacheEntry> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);
        template.setKeySerializer(stringSerializer);
        template.setHashKeySerializer(stringSerializer);
        template.setHashValueSerializer(contentSerializer);
        template.setValueSerializer(contentSerializer);
        template.setEnableDefaultSerializer(false);
        template.afterPropertiesSet();
        return template;
    }

    private RedisTemplate<String, String> stringRedisTemplate()
    {
        StringRedisSerializer stringSerializer = new StringRedisSerializer(StandardCharsets.UTF_8);
        Jackson2JsonRedisSerializer<String> contentSerializer = new Jackson2JsonRedisSerializer<>(String.class);
        RedisTemplate<String, String> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);
        template.setKeySerializer(stringSerializer);
        template.setHashKeySerializer(stringSerializer);
        template.setHashValueSerializer(contentSerializer);
        template.setValueSerializer(contentSerializer);
        template.setEnableDefaultSerializer(false);
        template.afterPropertiesSet();
        return template;
    }
}
    * 也可以进一步封装一个操作类OeeResourceCache,和一个数据类CacheEntry(包含创建时间)作为value放到redis中
@Configuration
public class OeeResourceCacheConfig {

    @Autowired
    private RedisRepository redisRepository;

    @Autowired
    private RedisSetRepository redisSetRepository;

    @Bean
    public OeeResourceCache oeeResourceCache() {
        return new OeeResourceCache(redisRepository);
    }

    @Bean
    public SynchronizationCache synchronizationCache() {
        return new SynchronizationCache(redisSetRepository);
    }
}

public class OeeResourceCache {

    private static final Logger LOG = LoggerFactory.getLogger(OeeResourceCache.class);

    private static final String OEE_RESOURCE_KEY = "oeeResource";

    private RedisRepository redisRepository;

    public OeeResourceCache(RedisRepository redisRepository) {
        this.redisRepository = redisRepository;
    }

    public void cacheOeeResource(String tenantId, String assetId, OeeResource oeeResource) {

        LOG.debug("Caching OeeResource for tenant {}, assetId {}", tenantId, assetId);
        LOG.trace("OeeResource: {}", oeeResource);

        Check.notNull(tenantId, "tenantId");
        Check.notNull(assetId, "assetId");

        String key = getKey(tenantId, assetId);

        CacheEntry cacheEntry = redisRepository.put(key, CacheEntry.from(oeeResource.toTimeSeriesValue()));

        LOG.info("OeeResource is cached for tenant {}, assetId {}", tenantId, assetId);
        LOG.trace("CacheEntry: {}", cacheEntry);
    }

    public OeeResource getOeeResource(String tenantId, String assetId) {

        LOG.debug("Getting OeeResource from cache for tenant {}, assetId {}", tenantId, assetId);

        Check.notNull(tenantId, "tenantId");
        Check.notNull(assetId, "assetId");

        String key = getKey(tenantId, assetId);

        CacheEntry cacheEntry = redisRepository.get(key);

        LOG.trace("CacheEntry: {}", cacheEntry);

        return cacheEntry == null ? null : OeeResource.from(cacheEntry.to(TimeSeriesValue.class));
    }

    public Optional<OeeResource> getOeeResource(String tenantId, String assetId, Instant time) {
        return Optional.ofNullable(getOeeResource(tenantId, assetId)).filter(Objects::nonNull)
                .filter(oeeResource -> oeeResource.getDate().equals(time));
    }

    private String getKey(String tenantId, String assetId) {
        return String.join(":", OEE_RESOURCE_KEY, tenantId, assetId);
    }
}

@Getter
@Setter
@ToString
public class CacheEntry {

    private String data;

    @JsonInstant
    private Instant createdAt;

    public static CacheEntry from(Object object) {
        CacheEntry entry = new CacheEntry();
        entry.setCreatedAt(Instant.now());
        entry.setData(Misc.serializeSafeJson(object));
        return entry;
    }

    public <T> T to(Class<T> theClass) {
        return Misc.deserializeSafeJson(data, theClass);
    }
}

Spring Boot - Spring Cache的更多相关文章

  1. spring boot guava cache 缓存学习

    http://blog.csdn.net/hy245120020/article/details/78065676 ****************************************** ...

  2. spring Boot+spring Cloud实现微服务详细教程第二篇

    上一篇文章已经说明了一下,关于spring boot创建maven项目的简单步骤,相信很多熟悉Maven+Eclipse作为开发常用工具的朋友们都一目了然,这篇文章主要讲解一下,构建spring bo ...

  3. spring Boot+spring Cloud实现微服务详细教程第一篇

    前些天项目组的大佬跟我聊,说项目组想从之前的架构上剥离出来公用的模块做微服务的开发,恰好去年的5/6月份在上家公司学习了国内开源的dubbo+zookeeper实现的微服务的架构.自己平时对微服务的设 ...

  4. Spring boot +Spring Security + Thymeleaf 认证失败返回错误信息

    [Please make sure to select the branch corresponding to the version of Thymeleaf you are using] Stat ...

  5. 255.Spring Boot+Spring Security:使用md5加密

    说明 (1)JDK版本:1.8 (2)Spring Boot 2.0.6 (3)Spring Security 5.0.9 (4)Spring Data JPA 2.0.11.RELEASE (5)h ...

  6. 256.Spring Boot+Spring Security: MD5是加密算法吗?

    说明 (1)JDK版本:1.8 (2)Spring Boot 2.0.6 (3)Spring Security 5.0.9 (4)Spring Data JPA 2.0.11.RELEASE (5)h ...

  7. Spring Boot+Spring Security:获取用户信息和session并发控制

    说明 (1)JDK版本:1.8(2)Spring Boot 2.0.6(3)Spring Security 5.0.9(4)Spring Data JPA 2.0.11.RELEASE(5)hiber ...

  8. Cola Cloud 基于 Spring Boot, Spring Cloud 构建微服务架构企业级开发平台

    Cola Cloud 基于 Spring Boot, Spring Cloud 构建微服务架构企业级开发平台: https://gitee.com/leecho/cola-cloud

  9. spring boot + spring batch 读数据库文件写入文本文件&读文本文件写入数据库

    好久没有写博客,换了一家新公司,原来的公司用的是spring,现在这家公司用的是spring boot.然后,项目组布置了一个任务,关于两个数据库之间的表同步,我首先想到的就是spring batch ...

  10. Spring Boot/Spring Cloud、ESB、Dubbo

    如何使用Spring Boot/Spring Cloud 实现微服务应用spring Cloud是一个基于Spring Boot实现的云应用开发工具,它为基于JVM的云应用开发中的配置管理.服务发现. ...

随机推荐

  1. CBV 验证装饰器的使用

    下面是3种方式: from django.shortcuts import render, redirect from django.views import View # Create your v ...

  2. Unity 输入与控制

    1. 鼠标输入 有关的方法和变量如下: 在 Unity 中,鼠标位置用屏幕的像素坐标表示,屏幕左下角为(0,0),右上角为(Screen.width,Screen.height). 2. 键盘操作 有 ...

  3. centos7+tomcat部署JavaWeb项目超详细步骤

    我们平时访问的网站大多都是发布在云服务器上的,比如阿里云.腾讯云等.对于新手,尤其是没有接触过linux系统的人而言是比较有困难的,而且至今使用云服务器也是有成本的,很多时候我们可以通过虚拟机自己搭建 ...

  4. Django中的DRF框架视图集使用

    1. 两个基类 1)APIView Django REST_framework 中所有视图的基类是APIView   父类是View 支持定义的属性: authentication_classes 列 ...

  5. MySQL数据库篇之库的增删改查

    主要内容: 一.系统数据库介绍 二.创建数据库 三.数据库增删改查 四.MySQL添加注释 1️⃣ 系统数据库介绍 1.初识sql语句 有了mysql这个数据库软件,就可以将程序员从对数据的管理中解脱 ...

  6. Android 多分辨率多屏幕适配

    请参见文章:http://blog.csdn.net/jiangxinyu/article/details/8598046 文章描述非常清晰.

  7. Avro总结(RPC/序列化)

    Avro(读音类似于[ævrə])是Hadoop的一个子项目,由Hadoop的创始人Doug Cutting(也是Lucene,Nutch等项目的创始人,膜拜)牵头开发,当前最新版本1.3.3.Avr ...

  8. 字符串查找 · Implement strStr()

    [抄题]: 对于一个给定的 source 字符串和一个 target 字符串,你应该在 source 字符串中找出 target 字符串出现的第一个位置(从0开始).如果不存在,则返回 -1. 如果 ...

  9. jquery简单ajax示例_读取json文件数据

    来自于<jquery权威指南> -------------------------------------- 点击button后,获取到json文件数据,显示如下: Json文件: [ { ...

  10. mybatis常用方法总结

    mybatis的强大特性之一就是动态SQL.我们在写复杂查询的时候,会发现复杂查询包括了各种各样的判断,我们很难一鼓作气的写出完美的查询.动态SQL语句可以帮助我们拼接不同的SQL语句,而已让我们的代 ...