【SpringBoot】在SpringBoot中使用Ehcache

2021年1月24日 23点热度 0条评论 来源: May的博客

SpringBoot提供了对缓存的支持,通过在启动类中添加@EnableCaching注解自动化配置合适的缓存管理器(CacheManager),Spring Boot根据下面的顺序去侦测缓存提供者:

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

SpringBoot的缓存机制:
SpringBoot缓存是依赖于由org.springframework.cache.Cache和org.springframework.cache.CacheManager接口实现的抽象高速缓存,不提供实际的存储,SpringBoot会根据实现自动配置合适的CacheManager,只要缓存支持通过@EnableCaching注释启用即可。基于Ehcache API实现的缓存操作工具类

SpringBoot 配置 EhCache 2.x
一、在pom文件中引入Ehcache依赖

二、在resources根目录下引入配置文件 ehcache.xml,增加需要的缓存配置

Ehcache.xml 文件配置详解:

  1. diskStore:为缓存路径,ehcache分为内存和磁盘两级,此属性定义磁盘的缓存位置。
  2. defaultCache:默认缓存策略,当ehcache找不到定义的缓存时,则使用这个缓存策略。只能定义一个。 name:缓存名称。
  3. maxElementsInMemory:缓存最大数目 maxElementsOnDisk:硬盘最大缓存个数。
  4. eternal:对象是否永久有效,一但设置了,timeout将不起作用。 overflowToDisk:是否保存到磁盘,当系统当机时
  5. timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
  6. timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。
  7. diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
  8. diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
  9. diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
  10. memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
  11. clearOnFlush:内存数量最大时是否清除。
  12. memoryStoreEvictionPolicy:可选策略有:LRU(最近最少使用,默认策略)、FIFO(先进先出)、LFU(最少访问次数)。
  13. FIFO,first in first out,先进先出。 LFU, Less Frequently
  14. Used,一直以来最少被使用的。如上面所讲,缓存的元素有一个hit属性,hit值最小的将会被清出缓存。 LRU,Least Recently Used,最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。

三、在SpringBoot启动类中添加开启缓存的注解@EnableCaching

一般情况下,我们在Sercive层对缓存进行操作。 Ehcache 在 Spring 中的注解如下:

  1. @Cacheable
    Spring在每次执行前都会检查Cache中是否存在相同key的缓存元素,如果存在就不再执行该方法,而是直接从缓存中获取结果进行返回,否则才会执行并将返回结果存入指定的缓存中。
  2. @CacheEvict
    清除缓存。
  3. @CachePut
    @CachePut也可以声明一个方法支持缓存功能。使用@CachePut标注的方法在执行前不会去检查缓存中是否存在之前执行过的结果,而是每次都会执行该方法,并将执行结果以键值对的形式存入指定的缓存中。

参数解释:

  1. value:缓存位置名称,不能为空,如果使用EHCache,就是ehcache.xml中声明的cache的name
  2. key:缓存的key,默认为空,既表示使用方法的参数类型及参数值作为key,支持SpEL(后面会有详细的讲解)
  3. condition:触发条件,只有满足条件的情况才会加入缓存,默认为空,既表示全部都加入缓存,支持SpEL
  4. allEntries:CacheEvict参数,true表示清除value中的全部缓存,默认为false

具体的Demo示例参看本人的Github:ehcache工具类以及在springboot中使用ehcache

附录:最近在面试中一个面试官问到@Cacheable 的key生成的问题,在这里总结一下:

key属性是用来指定Spring缓存方法的返回结果时对应的key的。该属性支持SpringEL表达式。当我们没有指定该属性时,Spring将使用默认策略生成key。

自定义策略是指我们可以通过Spring的EL表达式来指定我们的key。这里的EL表达式可以使用方法参数及它们对应的属性。使用方法参数时我们可以直接使用“#参数名”或者“#p参数index”。下面是几个使用参数作为key的示例。

1、用“#参数名”或者“#p参数index”

// key 当前类,缓存对象为返回值list
15     @Cacheable(value = {"lt.ecache"}, key = "#root.targetClass")
16     public List<Employee> getEmployees() {
17         System.out.println("*** getEmployees() 已经调用   ***");
18         List<Employee> list = new ArrayList<Employee>(5);
19         list.add(new Employee(1, "Ben", "Architect"));
20         list.add(new Employee(2, "Harley", "Programmer"));
21         list.add(new Employee(3, "Peter", "BusinessAnalyst"));
22         list.add(new Employee(4, "Sasi", "Manager"));
23         list.add(new Employee(5, "Abhi", "Designer"));
24         return list;
25     }
26 
27     // key id,缓存数据为返回值Employee对象
28     @Cacheable(value = "lt.ecache", key = "#id")
29     public Employee getEmployee(int id, List<Employee> employees) {
30         System.out.println("***  getEmployee(): " + id + " ***");
31         Employee emp = null;
32         for (Employee employee : employees) {
33             if (employee.getId() == id) {
34                 emp = employee;
35             }
36         }
37         return emp;
38     }
39 
40     // @CachePut会去替换缓存中的Employee对象为当前id对应的对象
41     @CachePut(value = "lt.ecache", key = "#id")
42     public Employee updateEmployee(int id, String designation, List<Employee> employees) {
43         System.out.println("*** updateEmployee()  " + id + " ***");
44         Employee emp = null;
45         int i = 0;
46         for (Employee employee : employees) {
47             if (employee.getId() == id) {
48                 employee.setDesignation(designation);
49                 emp = employee;
50             }
51         }
52         System.out.println(emp);
53         return emp;
54     }
55 
56     //key为参数中Employee对象的id,缓存指定id对应的Employee对象
57     @Cacheable(value = "lt.ecache", key = "#employee.id")
58     public Employee addEmployee(Employee employee, List<Employee> employees) {
59         System.out.println("*** addEmployee() : " + employee.getId() + " ***");
60         employees.add(employee);
61         System.out.println(employee);
62         return employee;
63     }
64 
65     //key为参数中的id,移除缓存,移除指定id对应的Employee对象
66     @CacheEvict(value = "lt.ecache", key = "#id")
67     public Employee removeEmployee(int id, List<Employee> employees) {
68         System.out.println("*** removeEmployee()  : " + id + " ***");
69         Employee emp = null;
70         int i = 0;
71         for (Employee employee : employees) {
72             if (employee.getId() == id) {
73                 emp = employee;
74             } else {
75                 i++;
76             }
77         }
78         employees.remove(i);
79         return emp;
80     }
81 
82     //key为当前类,移除缓存,移除employees列表对象
83     @CacheEvict(value = "lt.ecache", key = "#root.targetClass")
84     public List<Employee> removeAllEmployee(List<Employee> employees) {
85         System.out.println("*** removeAllEmployee()  :  ***");
86         employees.clear();
87         System.out.println(employees.size());
88         return employees;
89     }

当我们要使用root对象的属性作为key时我们也可以将“#root”省略,因为Spring默认使用的就是root对象的属性。

2、如果要调用当前类里面的方法(方法必须是public):

@Override
    @Cacheable(value={"TeacherAnalysis_public_chart"}, key="#root.target.getDictTableName() + '_' + #root.target.getFieldName()")
    public List<Map<String, Object>> getChartList(Map<String, Object> paramMap) {
    }
    public String getDictTableName(){
        return "";
    }
    public String getFieldName(){
        return "";
    }

    原文作者:May的博客
    原文地址: https://blog.csdn.net/lmb55/article/details/82392125
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系管理员进行删除。