https://blog.csdn.net/a67474506/article/details/52608855

Spring定义了org.springframework.cache.CacheManager和org.springframework.cache.Cache接口来统一不同的缓存技术,而SpringBoot为我们提供了自动配置多个CacheManager的实现

在不适用任何额外配置的情况下,默认使用SimpleCacheConfiguration

SpringBoot通过spring.cache为前缀来配置缓存

使用这些缓存实现的话,只需导入相关缓存的依赖,并在配置类中使用@EnableCaching开启缓存即可

Guava实现

这里简单介绍下使用Guava实现

引入的依赖

pom.xml

  1.  
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  2.  
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  3.  
    <modelVersion>4.0.0</modelVersion>
  4.  
    <groupId>com.ibigsea</groupId>
  5.  
    <artifactId>spirngboot-cache-demo</artifactId>
  6.  
    <version>0.0.1-SNAPSHOT</version>
  7.  
     
  8.  
     
  9.  
    <properties>
  10.  
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  11.  
    <boot.version>1.3.5.RELEASE</boot.version>
  12.  
    </properties>
  13.  
     
  14.  
    <dependencies>
  15.  
    <dependency>
  16.  
    <groupId>org.springframework.boot</groupId>
  17.  
    <artifactId>spring-boot-starter-web</artifactId>
  18.  
    <version>${boot.version}</version>
  19.  
    </dependency>
  20.  
    <dependency>
  21.  
    <groupId>org.springframework.boot</groupId>
  22.  
    <artifactId>spring-boot-starter-test</artifactId>
  23.  
    <version>${boot.version}</version>
  24.  
    <scope>test</scope>
  25.  
    </dependency>
  26.  
    <dependency>
  27.  
    <groupId>org.springframework.boot</groupId>
  28.  
    <artifactId>spring-boot-starter-cache</artifactId>
  29.  
    <version>${boot.version}</version>
  30.  
    </dependency>
  31.  
    <dependency>
  32.  
    <groupId>com.google.guava</groupId>
  33.  
    <artifactId>guava</artifactId>
  34.  
    <version>19.0</version>
  35.  
    </dependency>
  36.  
    </dependencies>
  37.  
    </project>

dataCache.java

  1.  
    package com.ibigsea.springboot_cache_demo.cache;
  2.  
     
  3.  
    import java.text.SimpleDateFormat;
  4.  
    import java.util.Date;
  5.  
    import java.util.HashMap;
  6.  
    import java.util.Map;
  7.  
     
  8.  
    import javax.annotation.PostConstruct;
  9.  
     
  10.  
    import org.springframework.cache.annotation.CacheConfig;
  11.  
    import org.springframework.cache.annotation.CacheEvict;
  12.  
    import org.springframework.cache.annotation.CachePut;
  13.  
    import org.springframework.cache.annotation.Cacheable;
  14.  
    import org.springframework.stereotype.Component;
  15.  
     
  16.  
    @Component
  17.  
    public class DataCache {
  18.  
     
  19.  
    private Map<Long, String> dataMap = new HashMap<>();
  20.  
     
  21.  
    /**
  22.  
    * 初始化
  23.  
    */
  24.  
    @PostConstruct
  25.  
    public void init() {
  26.  
    dataMap.put(1L, "张三");
  27.  
    dataMap.put(2L, "李四");
  28.  
    dataMap.put(3L, "王五");
  29.  
    }
  30.  
     
  31.  
    /**
  32.  
    * 查询
  33.  
    * 如果数据没有缓存,那么从dataMap里面获取,如果缓存了,
  34.  
    * 那么从guavaDemo里面获取
  35.  
    * 并且将缓存的数据存入到 guavaDemo里面
  36.  
    * 其中key 为 #id+dataMap
  37.  
    */
  38.  
    @Cacheable(value="guavaDemo" ,key="#id + 'dataMap'")
  39.  
    public String query(Long id) {
  40.  
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  41.  
    System.out.println(sdf.format(new Date()) + " : query id is " + id);
  42.  
    return dataMap.get(id);
  43.  
    }
  44.  
     
  45.  
    /**
  46.  
    * 插入 或者更新
  47.  
    * 插入或更新数据到dataMap中
  48.  
    * 并且缓存到 guavaDemo中
  49.  
    * 如果存在了那么更新缓存中的值
  50.  
    * 其中key 为 #id+dataMap
  51.  
    */
  52.  
    @CachePut(value="guavaDemo" ,key="#id + 'dataMap'")
  53.  
    public String put(Long id, String value) {
  54.  
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  55.  
    System.out.println(sdf.format(new Date()) + " : add data ,id is "+ id);
  56.  
    dataMap.put(id, value);
  57.  
    // data persistence
  58.  
    return value;
  59.  
    }
  60.  
     
  61.  
    /**
  62.  
    * 删除
  63.  
    * 删除dataMap里面的数据
  64.  
    * 并且删除缓存guavaDemo中的数据
  65.  
    * 其中key 为 #id+dataMap
  66.  
    */
  67.  
    @CacheEvict(value="guavaDemo" , key="#id + 'dataMap'")
  68.  
    public void remove(Long id) {
  69.  
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  70.  
    System.out.println(sdf.format(new Date()) + " : remove id is "+ id + " data");
  71.  
    dataMap.remove(id);
  72.  
    // data remove
  73.  
    }
  74.  
     
  75.  
     
  76.  
    }

关于缓存注解中的value,就是配置文件中的cache-names

关于注解中的key这个值,如果不指定的话 ,那么会取方法参数当做Key

application.yml

  1.  
    spring:
  2.  
    cache:
  3.  
    #缓存名称
  4.  
    cache-names: guavaDemo
  5.  
    #缓存最大数量500条, 缓存失效时间 6个小时
  6.  
    guava.spec: maximumSize=500,expireAfterWrite=360m

App.java

  1.  
    package com.ibigsea.springboot_cache_demo;
  2.  
     
  3.  
    import java.text.SimpleDateFormat;
  4.  
    import java.util.Date;
  5.  
     
  6.  
    import org.springframework.beans.factory.annotation.Autowired;
  7.  
    import org.springframework.boot.SpringApplication;
  8.  
    import org.springframework.boot.autoconfigure.SpringBootApplication;
  9.  
    import org.springframework.cache.annotation.EnableCaching;
  10.  
    import org.springframework.web.bind.annotation.RequestMapping;
  11.  
    import org.springframework.web.bind.annotation.RestController;
  12.  
     
  13.  
    import com.ibigsea.springboot_cache_demo.cache.DataCache;
  14.  
     
  15.  
    /**
  16.  
    * 是Spring Boot项目的核心注解,主要是开启自动配置
  17.  
    */
  18.  
    @SpringBootApplication // same as @Configuration @EnableAutoConfiguration @ComponentScan
  19.  
    @RestController
  20.  
    // 开启缓存
  21.  
    @EnableCaching
  22.  
    public class App {
  23.  
     
  24.  
    @Autowired
  25.  
    private DataCache dataCache;
  26.  
     
  27.  
    public static void main(String[] args) {
  28.  
    SpringApplication.run(App.class, args);
  29.  
    }
  30.  
     
  31.  
    @RequestMapping("/put")
  32.  
    public String put(Long id, String value) {
  33.  
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  34.  
    return sdf.format(new Date()) + " : value is " + dataCache.put(id, value) ;
  35.  
    }
  36.  
     
  37.  
    @RequestMapping("/get")
  38.  
    public String query(Long id){
  39.  
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  40.  
    return sdf.format(new Date()) + " : value is " +dataCache.query(id) ;
  41.  
    }
  42.  
     
  43.  
    @RequestMapping("/remove")
  44.  
    public String remove(Long id) {
  45.  
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  46.  
    dataCache.remove(id) ;
  47.  
    return sdf.format(new Date()) + " : success " ;
  48.  
    }
  49.  
     
  50.  
    }

运行结果

关于注解配置:

@Cacheable

@CacheEvict

@CachePut

和上面的一样,只是这个注解是用来更新或者插入数据到缓存中的,

其中key自己定义,返回值会缓存

还有就是SpringBoot会根据你的类路径里面的依赖jar,来确定使用什么类型进行缓存,所以基本是我们是不用配置spring.cache.type这个属性的

Redis实现

Redis缓存:

如果是用redis作为缓存的话

我们只需要引入redis相关依赖,修改yml配置属性

  1.  
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  2.  
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  3.  
    <modelVersion>4.0.0</modelVersion>
  4.  
    <groupId>com.ibigsea</groupId>
  5.  
    <artifactId>spirngboot-cache-demo</artifactId>
  6.  
    <version>0.0.1-SNAPSHOT</version>
  7.  
     
  8.  
     
  9.  
    <properties>
  10.  
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  11.  
    <boot.version>1.3.5.RELEASE</boot.version>
  12.  
    </properties>
  13.  
     
  14.  
    <dependencies>
  15.  
    <dependency>
  16.  
    <groupId>org.springframework.boot</groupId>
  17.  
    <artifactId>spring-boot-starter-web</artifactId>
  18.  
    <version>${boot.version}</version>
  19.  
    </dependency>
  20.  
    <dependency>
  21.  
    <groupId>org.springframework.boot</groupId>
  22.  
    <artifactId>spring-boot-starter-test</artifactId>
  23.  
    <version>${boot.version}</version>
  24.  
    <scope>test</scope>
  25.  
    </dependency>
  26.  
    <dependency>
  27.  
    <groupId>org.springframework.boot</groupId>
  28.  
    <artifactId>spring-boot-starter-cache</artifactId>
  29.  
    <version>${boot.version}</version>
  30.  
    </dependency>
  31.  
    <dependency>
  32.  
    <groupId>org.springframework.boot</groupId>
  33.  
    <artifactId>spring-boot-starter-redis</artifactId>
  34.  
    <version>${boot.version}</version>
  35.  
    </dependency>
  36.  
    <!-- <dependency> -->
  37.  
    <!-- <groupId>com.google.guava</groupId> -->
  38.  
    <!-- <artifactId>guava</artifactId> -->
  39.  
    <!-- <version>19.0</version> -->
  40.  
    <!-- </dependency> -->
  41.  
    </dependencies>
  42.  
    </project>

application.yml

  1.  
    spring:
  2.  
    cache:
  3.  
    #缓存名称
  4.  
    cache-names: guavaDemo
  5.  
    #缓存最大数量500条, 缓存失效时间 6个小时
  6.  
    #guava.spec: maximumSize=500,expireAfterWrite=360m
  7.  
    # REDIS (RedisProperties)
  8.  
    redis :
  9.  
    host : localhost # server host
  10.  
    port : 6379 # connection port
  11.  
    pool.max-idle : 8 # pool settings ...
  12.  
    pool.min-idle : 1
  13.  
    pool.max-active : 8
  14.  
    pool.max-wait : -1

就这样就OK了,代码什么的都是不用改变的,是不是很方便

测试结果


数据都会缓存到redis里面

其他的地方就不测试了 都是差不多的

使用其他实现导入对应的依赖,然后添加配置即可

注意:

如果使用guava缓存的时候 ,同时添加了redis的jar依赖,或者其他的依赖,可能会出现异常

这个时候加上 type: GUAVA 就可以

版权声明:本文为博主原创文章,博客地址:http://blog.csdn.net/a67474506?viewmode=contents https://blog.csdn.net/a67474506/article/details/52608855
 

guava cache

 

缓存是提高性能的一把利器。
常用到的缓存技术有分布式缓存,像Redis、MC;也有本地缓存,像ehcache、guava cache等。这里说的是本地缓存guava cache。

guava cache刚开始接触,这就记录下来。。

    public static void main(String[] args) throws ExecutionException, InterruptedException{
        //缓存接口这里是LoadingCache,LoadingCache在缓存项不存在时可以自动加载缓存
        LoadingCache<Integer,Student> studentCache
                //CacheBuilder的构造函数是私有的,只能通过其静态方法newBuilder()来获得CacheBuilder的实例
                = CacheBuilder.newBuilder()
                //设置并发级别为8,并发级别是指可以同时写缓存的线程数
                .concurrencyLevel(8)
                //设置写缓存后8秒钟过期
                .expireAfterWrite(8, TimeUnit.SECONDS)
          //设置写缓存后1秒钟刷新
         .refreshAfterWrite(1, TimeUnit. SECONDS)
                //设置缓存容器的初始容量为10
                .initialCapacity(10)
                //设置缓存最大容量为100,超过100之后就会按照LRU最近虽少使用算法来移除缓存项
                .maximumSize(100)
                //设置要统计缓存的命中率
                .recordStats()
                //设置缓存的移除通知
                .removalListener(new RemovalListener<Object, Object>() {
                    @Override
                    public void onRemoval(RemovalNotification<Object, Object> notification) {
                        System.out.println(notification.getKey() + " was removed, cause is " + notification.getCause());
                    }
                })
                //build方法中可以指定CacheLoader,在缓存不存在时通过CacheLoader的实现自动加载缓存
                .build(
                        new CacheLoader<Integer, Student>() {
                            @Override
                            public Student load(Integer key) throws Exception {
                                System.out.println("load student " + key);
                                Student student = new Student();
                                student.setId(key);
                                student.setName("name " + key);
                                return student;
                            }
                        }
                );         for (int i=0;i<20;i++) {
            //从缓存中得到数据,由于我们没有设置过缓存,所以需要通过CacheLoader加载缓存数据
            Student student = studentCache.get(1);
            System.out.println(student);
            //休眠1秒
            TimeUnit.SECONDS.sleep(1);
        }         System.out.println("cache stats:");
        //最后打印缓存的命中率等 情况
        System.out.println(studentCache.stats().toString());
    }

还有另一种方法

package com;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; import com.google.common.cache.*; /**
* @author 作者 PZhang E-mail:pzhang@rxhui.com
* @date 创建时间:2017-2-15 上午9:58:00
* @version 1.0
* @parameter
* @return
*/
public class CacheModel {
public Student getStudent(Integer key){
System.out.println("load student " + key);
Student student = new Student();
student.setId(key);
student.setName("name " + key);
return student;
}
//load Method
public void loadCacheA() throws Exception{
LoadingCache<Integer,Student> studentCache= CacheBuilder.newBuilder().concurrencyLevel(8).
expireAfterWrite(8, TimeUnit.SECONDS).refreshAfterWrite(1, TimeUnit. SECONDS).initialCapacity(10).maximumSize(100)
.recordStats().removalListener(new RemovalListener<Object, Object>() {
public void onRemoval(RemovalNotification<Object, Object> notification) {
System.out.println(notification.getKey() + " was removed, cause is " + notification);}
}).build(
new CacheLoader<Integer, Student>() {
@Override
public Student load(Integer key) throws Exception {
return getStudent(key);
}
}
); for (int i=0;i<20;i++) {
Student student = studentCache.get(1);
System.out.println(student);
TimeUnit.SECONDS.sleep(1);
} System.out.println("cache stats:");
System.out.println(studentCache.stats().toString()); }
//call back Method
public void loadCacheB(final Integer key) throws Exception{
Cache<Integer, Student> cache = CacheBuilder.newBuilder().maximumSize(1000).recordStats().expireAfterWrite(8, TimeUnit.SECONDS).build(); for (int i=0;i<20;i++) {
System.out.println(cache.get(key, new Callable<Student>() {
public Student call() {
return getStudent(key);
}
}));
TimeUnit.SECONDS.sleep(1);
} System.out.println("cache stats:");
System.out.println(cache.stats().toString());
} public static void main(String[] args) throws Exception {
CacheModel cache = new CacheModel();
cache.loadCacheB(2);
} }

  guava Cache数据移除:

  guava做cache时候数据的移除方式,在guava中数据的移除分为被动移除和主动移除两种。
  被动移除数据的方式,guava默认提供了三种方式:
  1.基于大小的移除:看字面意思就知道就是按照缓存的大小来移除,如果即将到达指定的大小,那就会把不常用的键值对从cache中移除。
  定义的方式一般为 CacheBuilder.maximumSize(long),还有一种一种可以算权重的方法,个人认为实际使用中不太用到。就这个常用的来看有几个注意点,
    其一,这个size指的是cache中的条目数,不是内存大小或是其他;
    其二,并不是完全到了指定的size系统才开始移除不常用的数据的,而是接近这个size的时候系统就会开始做移除的动作;
    其三,如果一个键值对已经从缓存中被移除了,你再次请求访问的时候,如果cachebuild是使用cacheloader方式的,那依然还是会从cacheloader中再取一次值,如果这样还没有,就会抛出异常
  2.基于时间的移除:guava提供了两个基于时间移除的方法
    expireAfterAccess(long, TimeUnit)  这个方法是根据某个键值对最后一次访问之后多少时间后移除
    expireAfterWrite(long, TimeUnit)  这个方法是根据某个键值对被创建或值被替换后多少时间移除
  3.基于引用的移除:
  这种移除方式主要是基于java的垃圾回收机制,根据键或者值的引用关系决定移除
  主动移除数据方式,主动移除有三种方法:
  1.单独移除用 Cache.invalidate(key)
  2.批量移除用 Cache.invalidateAll(keys)
  3.移除所有用 Cache.invalidateAll()
  如果需要在移除数据的时候有所动作还可以定义Removal Listener,但是有点需要注意的是默认Removal Listener中的行为是和移除动作同步执行的,如果需要改成异步形式,可以考虑使用RemovalListeners.asynchronous(RemovalListener, Executor)

 
 
标签: cache

SpringBoot学习笔记(6) SpringBoot数据缓存Cache [Guava和Redis实现]的更多相关文章

  1. 微信小程序开发:学习笔记[9]——本地数据缓存

    微信小程序开发:学习笔记[9]——本地数据缓存 快速开始 说明 本地数据缓存是小程序存储在当前设备上硬盘上的数据,本地数据缓存有非常多的用途,我们可以利用本地数据缓存来存储用户在小程序上产生的操作,在 ...

  2. SpringBoot学习笔记(10)-----SpringBoot中使用Redis/Mongodb和缓存Ehcache缓存和redis缓存

    1. 使用Redis 在使用redis之前,首先要保证安装或有redis的服务器,接下就是引入redis依赖. pom.xml文件如下 <dependency> <groupId&g ...

  3. springboot学习笔记-5 springboot整合shiro

    shiro是一个权限框架,具体的使用可以查看其官网 http://shiro.apache.org/  它提供了很方便的权限认证和登录的功能. 而springboot作为一个开源框架,必然提供了和sh ...

  4. springboot学习笔记-6 springboot整合RabbitMQ

    一 RabbitMQ的介绍 RabbitMQ是消息中间件的一种,消息中间件即分布式系统中完成消息的发送和接收的基础软件.这些软件有很多,包括ActiveMQ(apache公司的),RocketMQ(阿 ...

  5. SpringBoot学习笔记(11)-----SpringBoot中使用rabbitmq,activemq消息队列和rest服务的调用

    1. activemq 首先引入依赖 pom.xml文件 <dependency> <groupId>org.springframework.boot</groupId& ...

  6. SpringBoot学习笔记(9)----SpringBoot中使用关系型数据库以及事务处理

    在实际的运用开发中,跟数据库之间的交互是必不可少的,SpringBoot也提供了两种跟数据库交互的方式. 1. 使用JdbcTemplate 在SpringBoot中提供了JdbcTemplate模板 ...

  7. SpringBoot学习笔记(4)----SpringBoot中freemarker、thymeleaf的使用

    1. freemarker引擎的使用 如果你使用的是idea或者eclipse中安装了sts插件,那么在新建项目时就可以直接指定试图模板 如图: 勾选freeMarker,此时springboot项目 ...

  8. 【转】SpringBoot学习笔记(7) SpringBoot整合Dubbo(使用yml配置)

    http://blog.csdn.net/a67474506/article/details/61640548 Dubbo是什么东西我这里就不详细介绍了,自己可以去谷歌 SpringBoot整合Dub ...

  9. SpringBoot学习笔记(16)----SpringBoot整合Swagger2

    Swagger 是一个规范和完整的框架,用于生成,描述,调用和可视化RESTful风格的web服务 http://swagger.io Springfox的前身是swagger-springmvc,是 ...

随机推荐

  1. tomcat server.xml各个端口的作用

    <Server port="8005" shutdown="SHUTDOWN"> <!-- port:指定一个端口,这个端口负责监听关闭Tom ...

  2. MyBatis映射文件5

    返回map     Map<String,Object> getEmpByResMap(Integer id); <select id="getEmpByResMap&qu ...

  3. java学习之—使用栈实现字符串数字四则运算

    /** * 使用栈存储后缀表达式 * Create by Administrator * 2018/6/13 0013 * 下午 2:25 **/ public class StackX { priv ...

  4. mysql 中出现:不能打开到主机的连接,在端口3306: 连接失败

    由于某种原因,在服务器部署,然后mysql就连接不上了, navicat查看数据库正常,telnet怎么都不同,总会卡一会儿说遗失主机,最后终于找到解决办法 http://www.51testing. ...

  5. ReCAPTCHA & 手势验证

    手势验证 recaptcha https://www.vaptcha.com/ https://www.vaptcha.com/document https://www.iviewui.com/com ...

  6. linux 查看路由表

    随便转载,保留出处:http://www.cnblogs.com/aaron-agu/ route –n

  7. todo项目总结

    vue+webpack项目工程配置 1.vue-loader+webpack项目配置 2.webpack配置项目加载各种静态资源 3.webpack-dev-server的配置和使用 安装: pack ...

  8. 关于SQL查询语句中的LIKE模糊查询的解释

    LIKE语句的语法格式为: select * from 表名 where 字段名 like 对应值(字符串) 注:主要是针对字符型字段的,它的作用是在一个字符型字段列中检索包含对应字符串的. 下面列举 ...

  9. 数据库语法group by

    因为在做pgsql和mysql数据库时group by 有报错,但是在以前做mysql5.6的时候没有问题,虽然知道时违反了sql的语法问题,但是没有搞清楚什么原因,也找了不少资料,查找原因,在盆友的 ...

  10. Nginx 缓存针对打开的文件句柄与原文件信息

    L:108 open_file_cache syntax: open_file_cache off;   open_file_cache max=N[inactive=time](inactive表示 ...