GVKun编程网logo

Spring Boot,使用EhCache进行缓存(springboot本地缓存ehcache)

15

本文将带您了解关于SpringBoot,使用EhCache进行缓存的新内容,同时我们还将为您解释springboot本地缓存ehcache的相关知识,另外,我们还将为您提供关于Cache系列:spri

本文将带您了解关于Spring Boot,使用EhCache进行缓存的新内容,同时我们还将为您解释springboot本地缓存ehcache的相关知识,另外,我们还将为您提供关于Cache系列:spring-cache简单三步快速应用ehcache3.x-jcache缓存(spring4.x)、Java SpringBoot 使用 Redis 缓存和 Ehcache、java – Spring Boot,使用EhCache进行缓存、Spring Boot 2.x基础教程:EhCache缓存的使用的实用信息。

本文目录一览:

Spring Boot,使用EhCache进行缓存(springboot本地缓存ehcache)

Spring Boot,使用EhCache进行缓存(springboot本地缓存ehcache)

我需要在应用程序中缓存一些数据,并且我正在考虑使用Ehcache。我有几个问题:

  1. 我是否需要其他服务器进行Ehcache?
  2. 我是否需要其他客户端来使用Ehcache?
  3. Ehcache如何与多个实例一起使用?甚至可以使用Ehcache创建类似共享缓存的内容吗?

答案1

小编典典

我是否需要其他服务器进行Ehcache?

您可以在独立模式下使用Ehcache。在这种拓扑中,缓存数据保存在应用程序节点中。因此,在这种模式下,您将不需要其他服务器。Ehcache还提供了另外两种模式:

  1. 分布式 –数据保存在远程服务器(或服务器阵列)中,每个应用程序节点中保存有一部分最近使用的数据。此拓扑提供了一组丰富的一致性选项。在集群或横向扩展应用程序环境中,推荐使用分布式拓扑。它提供了最高水平的性能,可用性和可伸缩性。

分布式拓扑可作为Terracotta开源产品提供,没有客户端限制,但对Terracotta群集大小有限制。使用商用BigMemory
Max时,这些将被删除。

  1. 复制 -缓存的数据集保存在每个应用程序节点中,并且无需锁定即可在节点之间复制或使数据无效。复制可以是异步的也可以是同步的,其中传播发生时写线程将阻塞。此拓扑唯一支持的一致性模式是弱一致性。

我是否需要其他客户端来使用Ehcache?

您应该使用Ehcache库才能与Ehache通信。但是Spring提供了一个缓存抽象,它可以更优雅地工作,并且还具有独立于底层缓存实现的优点。因此,如果您使用Spring
Caching
Abstraction,则可以轻松地从Ehcache切换到Hazelcast。您可以在此处阅读有关Spring Caching Abstraction的更多信息。

Spring Boot提供了spring-boot-starter-cache启动程序包,CacheManager只要启用了缓存支持,它就会根据实现自动配置合适的启动程序包。

Ehcache如何与多个实例一起使用?甚至可以使用Ehcache创建类似共享缓存的内容吗?

引用Ehcache文档:

Ehcache提供了进程内缓存,您可以在多个节点之间进行复制。它还是Terracotta的商业缓存和内存中数据存储产品BigMemory
Go和BigMemory Max的核心。BigMemory
Max随附的Terracotta服务器阵列可实现具有TB级缓存的混合进程内/进程外配置。有关Terracotta的BigMemory产品的信息,请参阅http://terracotta.org/documentation上的BigMemory
Go和BigMemory Max产品文档。

如上所述,Ehcache提供了一个免费的群集选项。对于此要求,Redis和Hazelcast也是不错的选择。

Cache系列:spring-cache简单三步快速应用ehcache3.x-jcache缓存(spring4.x)

Cache系列:spring-cache简单三步快速应用ehcache3.x-jcache缓存(spring4.x)

前言:本项目基于spring4.x构建,使用ehcache3.5.2和JCache(jsr107规范)

一、依赖

    除了ehcache和cache-api外,注意引用spring-context-support

  1.                    
  2.                      <dependency>
  3.                          <groupId>org.springframework</groupId>
  4.                          <artifactId>spring-context-support</artifactId>
  5.                          <version>4.3.16.RELEASE</version>
  6.                      </dependency>
  7.      <dependency>
  8.      <groupId>org.ehcache</groupId>
  9.      <artifactId>ehcache</artifactId>
  10.      <version>3.5.2</version>
  11. </dependency>
  12. <dependency>
  13.      <groupId>javax.cache</groupId>
  14.      <artifactId>cache-api</artifactId>
  15.      <version>1.0.0</version>
  16. </dependency>

 

二、配置

1、ehcache配置

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <ehcache:config
  3. xmlns:ehcache="http://www.ehcache.org/v3"
  4. xmlns:jcache="http://www.ehcache.org/v3/jsr107">
  5.  
  6. <ehcache:service>
  7. <jcache:defaults>
  8. <jcache:cache name="default" template="myDefaultTemplate"/>
  9. </jcache:defaults>
  10. </ehcache:service>
  11.  
  12. <ehcache:cache alias="allCameraCache">
  13. <ehcache:key-type copier="org.ehcache.impl.copy.SerializingCopier">java.lang.String</ehcache:key-type>
  14. <ehcache:value-type copier="org.ehcache.impl.copy.SerializingCopier">java.lang.String</ehcache:value-type>
  15. <ehcache:expiry>
  16. <ehcache:tti unit="minutes">20</ehcache:tti><!-- 数据过期时间20分钟 -->
  17. </ehcache:expiry>
  18. <ehcache:heap unit="entries">200</ehcache:heap><!-- 最多缓存200个对象 -->
  19. </ehcache:cache>
  20.  
  21. <!-- 使用模板,可以覆盖模板的属性 -->
  22. <ehcache:cache alias="cameraCache" uses-template="myDefaultTemplate">
  23. <ehcache:key-type>java.lang.Object</ehcache:key-type>
  24. <ehcache:value-type>java.lang.Object</ehcache:value-type>
  25. <ehcache:expiry>
  26. <ehcache:tti unit="minutes">30</ehcache:tti><!-- 数据过期时间30分钟,覆盖模板默认属性 -->
  27. </ehcache:expiry>
  28. <ehcache:heap unit="entries">500</ehcache:heap><!-- 最多缓存500个对象 -->
  29. </ehcache:cache>
  30.  
  31. <!-- 默认模板 -->
  32. <ehcache:cache-template name="myDefaultTemplate">
  33. <ehcache:expiry>
  34. <ehcache:none/><!-- 缓存永不过期 -->
  35. </ehcache:expiry>
  36. </ehcache:cache-template>
  37.  
  38. </ehcache:config>

 

2、spring配置

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:context="http://www.springframework.org/schema/context"
  5. xmlns:cache="http://www.springframework.org/schema/cache"
  6. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
  7. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
  8. http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">
  9. <!--eguid博客地址:http://bog.eguid.cc-->
  10. <cache:annotation-driven cache-manager="cacheManager" /><!--扫描cache注解,如果已有可以不要-->
  11. <context:component-scan base-package="cc.eguid.cache" /><!--扫描路径 -->
  12. <!-- jcache缓存 -->
  13. <bean id="jCacheManager" class="org.springframework.cache.jcache.JCacheManagerFactoryBean">
  14.      <property name="cacheManagerUri" value="classpath:config/ehcache.xml" /> <!--改成配置文件对应的路径-->
  15. </bean>
  16. <bean id="cacheManager" class="org.springframework.cache.jcache.JCacheCacheManager">
  17. <property name="cacheManager" ref="jCacheManager" />
  18. </bean>
  19. </beans>

 

三、使缓存生效

1、注解方式使用

@Cacheable(value="cameraCache",key="#userid")

public String getCameraList(String userid,Integer otherparam) {

...

}

spring-cache的注解比较简单就不再赘述了。

 

Java SpringBoot 使用 Redis 缓存和 Ehcache

Java SpringBoot 使用 Redis 缓存和 Ehcache

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
         updateCheck="false">
    <!--
       该文件存放在resources目录下  application.properties文件添加spring.cache.ehcache.config=classpath:/ehcache.xml
       diskStore:为缓存路径,ehcache分为内存和磁盘两级,此属性定义磁盘的缓存位置。参数解释如下:
       user.home – 用户主目录
       user.dir  – 用户当前工作目录
       java.io.tmpdir – 默认临时文件路径
     -->
    <diskStore path="java.io.tmpdir/Tmp_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:内存数量最大时是否清除。
      memoryStoreEvictionPolicy:可选策略有:LRU(最近最少使用,默认策略)、FIFO(先进先出)、LFU(最少访问次数)。
      FIFO,first in first out,这个是大家最熟的,先进先出。
      LFU, Less Frequently Used,就是上面例子中使用的策略,直白一点就是讲一直以来最少被使用的。如上面所讲,缓存的元素有一个hit属性,hit值最小的将会被清出缓存。
      LRU,Least Recently Used,最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。
   -->
    <defaultCache
            eternal="false"
            maxElementsInMemory="10000"
            overflowToDisk="false"
            diskPersistent="false"
            timeToIdleSeconds="1800"
            timeToLiveSeconds="259200"
            memoryStoreEvictionPolicy="LRU"/>

    <cache
            name="product"
            eternal="false"
            maxElementsInMemory="5000"
            overflowToDisk="false"
            diskPersistent="false"
            timeToIdleSeconds="1800"
            timeToLiveSeconds="1800"
            memoryStoreEvictionPolicy="LRU"/>

</ehcache>
package ehcache.demo.controller;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import ehcache.demo.entity.Product;
import ehcache.demo.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.sound.midi.Soundbank;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Controller
public class ProductController {
    @Autowired
    private ProductService productService;

    /**
     * 获取所有商品 使用redis缓存
     *
     * @return
     */
    @SuppressWarnings("unchecked")
    @RequestMapping("getall")
    @ResponseBody
    public Object GetAllProduct() {

        /**************** 高并发环境下的缓存穿透测试 **********************/
        /*
        // 线程,该线程调用底层的查询所有商品方法
        Runnable runnable = new Runnable() {
            public void run() {
                productService.getAll();
            }
        };

        // 模拟多线程测试高并发穿透问题
        ExecutorService executorService = Executors.newFixedThreadPool(6);
        for (int i = 0; i < 1000; i++) {
            executorService.submit(runnable);
        }
        */

        return productService.getAll();
    }

    /**
     * 获取分页商品
     *
     * @return
     */
    @RequestMapping("getpage")
    @ResponseBody
    public Object GetPage() {
        // 分页查询
        PageHelper.startPage(1, 5);
        List<Product> listProducts = productService.getAll();
        PageInfo<Product> productPageInfo = new PageInfo(listProducts);
        return productPageInfo;
    }

    /**
     * 获取单个商品 使用ehcache
     *
     * @param id
     * @return
     */
    @RequestMapping("getone/{id}")
    @ResponseBody
    public Object GetProduct(@PathVariable int id) {

        Product product = productService.selectByPrimaryKey(id);
        System.out.println("第一次查询" + product.toString());
        product = productService.selectByPrimaryKey(id);
        System.out.println("第二次查询" + product.toString());
        product = productService.selectByPrimaryKey(id);
        System.out.println("第三次查询" + product.toString());
        product = productService.selectByPrimaryKey(id);
        System.out.println("第四次查询" + product.toString());
        return product;
    }


    /**
     * 返回json测试
     *
     * @return
     */
    @RequestMapping("json")
    @ResponseBody
    private Object json() {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("name", "测试姓名");
        map.put("address", "深圳市南山区");
        return map;
    }
}
package ehcache.demo.service;

import ehcache.demo.entity.Product;

import java.util.List;

public interface ProductService {

	public Product selectByPrimaryKey(int id);

	public List<Product> getAll() ;

	public Object deleteProduct(int id);

	public Object addProduct(Product product);

	public Object updateProduct(Product product);
}
package ehcache.demo.service.Impl;

import com.alibaba.fastjson.JSON;
import ehcache.demo.entity.Product;
import ehcache.demo.mapper.ProductMapper;
import ehcache.demo.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class ProductServiceImpl implements ProductService {

    @Autowired
    private ProductMapper productMapper;

    /* 注入springboot自动配置的redis */
    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;

    @Cacheable(value = "product", key = "#id")
    public Product selectByPrimaryKey(int id) {
        return productMapper.selectByPrimaryKey(id);
    }

    public List<Product> getAll() {
        // 创建redis序列化构造器,方便存储可视化
        RedisSerializer<?> redisSerializer = new StringRedisSerializer();
        redisTemplate.setKeySerializer(redisSerializer);  //序列化key

        // 查询redis缓存
        @SuppressWarnings("unchecked")
        List<Product> productList = (List<Product>) redisTemplate.opsForValue().get("allproducts");

        /* 使用双重验证锁解决高并发环境下的缓存穿透问题 */
        if (productList == null) { // 第一重验证
            synchronized (this) {
                productList = (List<Product>) redisTemplate.opsForValue().get("allproducts");
                if (productList == null) { // 第二重验证
                    System.out.println("查询数据库............");
                    // 缓存为空,则查询数据 entity需支持序列化 implements Serializable
                    productList = productMapper.getAll();
                    // 数据库查询的数据保存至缓存
                    redisTemplate.opsForValue().set("allproducts", productList);
                } else {
                    System.out.println("查询缓存............");
                }
            }
        } else {
            System.out.println("查询缓存............");
        }
        return productList;
    }

    public Object deleteProduct(int id) {
        return productMapper.deleteByPrimaryKey(id);
    }

    @Override
    public Object addProduct(Product product) {
        return productMapper.insert(product);
    }

    public Object updateProduct(Product product) {
        return productMapper.updateByPrimaryKey(product);
    }
}

pom.xml 文件配置

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.9.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>Ehcache</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.61</version>
        </dependency>

        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>4.6.7</version>
        </dependency>

        <!--添加热部署依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
            <scope>true</scope>
        </dependency>

        <!--mybatis spring起步依赖-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.0</version>
        </dependency>


        <!-- tomcat对jsp支持开启 -->
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
        </dependency>
        <!--jstl支持开启 -->
        <dependency>
            <groupId>jstl</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
        <!-- servlet支持开启 -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
        </dependency>
        <!--jstl支持开启 -->
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>jsp-api</artifactId>
            <version>2.2</version>
            <scope>provided</scope>
        </dependency>

        <!-- 分页插件开始 -->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.2.7</version>
        </dependency>
        <!-- 分页插件结束 -->

        <!-- mysql支持开始 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.13</version>
        </dependency>
        <!-- mysql支持结束 -->

        <!-- 加载redis -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <!-- Spring Boot 缓存支持启动器 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>
        <!-- Ehcache 坐标 -->
        <dependency>
            <groupId>net.sf.ehcache</groupId>
            <artifactId>ehcache</artifactId>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>

        <!--添加防止生成后找不到XML、YML、properties文件-->
        <resources>
            <resource>
                <directory>src/main/webapp</directory>
                <targetPath>META-INF/resources</targetPath>
                <includes>
                    <include>**/*.*</include>
                </includes>
            </resource>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.yml</include>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>false</filtering>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.*</include>
                </includes>
                <filtering>false</filtering>
            </resource>
        </resources>
    </build>

</project>

java – Spring Boot,使用EhCache进行缓存

java – Spring Boot,使用EhCache进行缓存

我需要在我的应用程序中缓存一些数据,我正在考虑使用Ehcache.我有几个问题:

> Ehcache需要另一台服务器吗?
>我是否需要其他客户与Ehcache合作?
> Ehcache如何处理多个实例?甚至可以使用Ehcache创建共享缓存之类的东西吗?

最佳答案

Do I need another server for Ehcache?

您可以在独立模式下使用Ehcache.在此拓扑中,缓存数据保存在应用程序节点中.所以在这种模式下你不需要另一台服务器. Ehcache还提供two other modes:

>分布式 – 数据保存在远程服务器(或服务器阵列)中,每个数据中都包含最近使用的数据子集
应用节点.此拓扑提供了丰富的一致性
选项.分布式拓扑是a中推荐的方法
集群或扩展的应用程序环境.它提供了
最高级别的性能,可用性和可伸缩性.

分布式拓扑以Terracotta open source offering的形式提供,没有客户端限制,但对Terracotta集群大小有限制.使用商业BigMemory Max时将删除这些内容.
>复制 ​​- 缓存的数据集保存在每个应用程序节点中,数据在节点之间复制或无效
锁定.复制可以是异步的,也可以是同步的
写入线程在传播发生时阻塞的位置.唯一的
此拓扑中支持的一致性模式是弱一致性.

Do I need some another client to work with Ehcache?

您应该使用Ehcache库以便能够与Ehache通信.但是Spring提供了一个缓存抽象,它更优雅,并且还具有独立于底层缓存实现的优势.因此,如果您使用Spring Caching Abstraction,您可以轻松地将表单Ehcache切换到Hazelcast.您可以在here中阅读有关Spring Caching Abstraction的更多信息.

Spring Boot提供了spring-boot-starter-cache启动程序包,只要启用了缓存支持,它就会根据实现自动配置合适的CacheManager.

How Ehcache works with multiple instances? Is it even possible to
create something like shared cache using Ehcache?

引自Ehcache documentation:

Ehcache provides in-process cache,which you can replicate across
multiple nodes. It is also at the core of BigMemory Go and BigMemory
Max,Terracotta’s commercial caching and in-memory data-storage
products. The Terracotta Server Array provided with BigMemory Max
enables mixed in-process/out-of-process configurations with
terabyte-size caches. For information about Terracotta’s BigMemory
offerings,see the BigMemory Go and BigMemory Max product
documentation at 07006.

如上所述,Ehcache提供了一个免费的群集选项.
对于这个要求,Redis和Hazelcast也是不错的选择.

Spring Boot 2.x基础教程:EhCache缓存的使用

Spring Boot 2.x基础教程:EhCache缓存的使用

上一篇我们学会了如何使用Spring Boot使用进程内缓存在加速数据访问。可能大家会问,那我们在Spring Boot中到底使用了什么缓存呢?

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

  • Generic
  • JCache (JSR-107) (EhCache 3, Hazelcast, Infinispan, and others)
  • EhCache 2.x
  • Hazelcast
  • Infinispan
  • Couchbase
  • Redis
  • Caffeine
  • Simple

除了按顺序侦测外,我们也可以通过配置属性spring.cache.type来强制指定。我们也可以通过debug调试查看cacheManager对象的实例来判断当前使用了什么缓存。在上一篇中,我们也展示了如何去查看当前使用情况。

当我们不指定具体其他第三方实现的时候,Spring Boot的Cache模块会使用ConcurrentHashMap来存储。而实际生产使用的时候,因为我们可能需要更多其他特性,往往就会采用其他缓存框架,所以接下来我们会分几篇分别介绍几个常用优秀缓存的整合与使用。

使用EhCache

本篇我们将介绍如何在Spring Boot中使用EhCache进程内缓存。这里我们将沿用上一篇的案例结果来进行改造,以实现EhCache的使用。

先回顾下这个基础案例的三个部分:

User实体的定义

@Entity
@Data
@NoArgsConstructor
public class User {

    @Id
    @GeneratedValue
    private Long id;

    private String name;
    private Integer age;

    public User(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
}

User实体的数据访问实现(涵盖了缓存注解)

@CacheConfig(cacheNames = "users")
public interface UserRepository extends JpaRepository<User, Long> {

    @Cacheable
    User findByName(String name);

}

测试验证用例(涵盖了CacheManager的注入,可用来观察使用的缓存管理类)

@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
public class Chapter51ApplicationTests {

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private CacheManager cacheManager;

    @Test
    public void test() throws Exception {
        // 创建1条记录
        userRepository.save(new User("AAA", 10));

        User u1 = userRepository.findByName("AAA");
        System.out.println("第一次查询:" + u1.getAge());

        User u2 = userRepository.findByName("AAA");
        System.out.println("第二次查询:" + u2.getAge());
    }

}

接下来我们通过下面的几步操作,就可以轻松的把上面的缓存应用改成使用ehcache缓存管理。

第一步:在pom.xml中引入ehcache依赖

<dependency>
    <groupId>net.sf.ehcache</groupId>
    <artifactId>ehcache</artifactId>
</dependency>
在Spring Boot的parent管理下,不需要指定具体版本,会自动采用Spring Boot中指定的版本号。

第二步:在src/main/resources目录下创建:ehcache.xml

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="ehcache.xsd">

    <cache name="users"
           maxEntriesLocalHeap="200"
           timeToLiveSeconds="600">
    </cache>

</ehcache>

完成上面的配置之后,再通过debug模式运行单元测试,观察此时CacheManager已经是EhCacheManager实例,说明EhCache开启成功了。或者在测试用例中加一句CacheManager的输出,比如:

@Autowired
private CacheManager cacheManager;

@Test
public void test() throws Exception {
    System.out.println("CacheManager type : " + cacheManager.getClass());

    userRepository.save(new User("AAA", 10));

    User u1 = userRepository.findByName("AAA");
    System.out.println("第一次查询:" + u1.getAge());

    User u2 = userRepository.findByName("AAA");
    System.out.println("第二次查询:" + u2.getAge());
}

执行测试输出可以得到:

CacheManager type : class org.springframework.cache.ehcache.EhCacheCacheManager
Hibernate: select next_val as id_val from hibernate_sequence for update
Hibernate: update hibernate_sequence set next_val= ? where next_val=?
Hibernate: insert into user (age, name, id) values (?, ?, ?)
2020-07-14 18:09:28.465  INFO 58538 --- [           main] o.h.h.i.QueryTranslatorFactoryInitiator  : HHH000397: Using ASTQueryTranslatorFactory
Hibernate: select user0_.id as id1_0_, user0_.age as age2_0_, user0_.name as name3_0_ from user user0_ where user0_.name=?
第一次查询:10
第二次查询:10

可以看到:

  1. 第一行输出的CacheManager type为org.springframework.cache.ehcache.EhCacheCacheManager,而不是上一篇中的ConcurrentHashMap了。
  2. 第二次查询的时候,没有输出SQL语句,所以是走的缓存获取

整合成功!

代码示例

本文的相关例子可以查看下面仓库中的chapter5-2目录:

  • Github:https://github.com/dyc87112/SpringBoot-Learning/
  • Gitee:https://gitee.com/didispace/SpringBoot-Learning/

如果您觉得本文不错,欢迎Star支持,您的关注是我坚持的动力!

本文首发:Spring Boot 2.x基础教程:EhCache缓存的使用,转载请注明出处。
欢迎关注我的公众号:程序猿DD,获得独家整理的学习资源和日常干货推送。
本系列教程点击直达目录

关于Spring Boot,使用EhCache进行缓存springboot本地缓存ehcache的问题我们已经讲解完毕,感谢您的阅读,如果还想了解更多关于Cache系列:spring-cache简单三步快速应用ehcache3.x-jcache缓存(spring4.x)、Java SpringBoot 使用 Redis 缓存和 Ehcache、java – Spring Boot,使用EhCache进行缓存、Spring Boot 2.x基础教程:EhCache缓存的使用等相关内容,可以在本站寻找。

本文标签: