Ehcache 缓存

Ehcache 缓存

Ehcache缓存在Java开发领域已时久负盛名,在SpringBoot中,只需一个配置文件就可以将Ehcache集成到项目中。具体的使用步骤如下:

1. 创建项目,添加缓存依赖

创建SpringBoot项目,添加spring-boot-starter-cache依赖以及Ehcache依赖,代码如下:

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>
        <dependency>
            <groupId>org.ehcache</groupId>
            <artifactId>ehcache</artifactId>
            <version>3.8.1</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

2.添加缓存配置文件

如果Ehcache的依赖存在,并且在classpath下有个名为ehcache.xml的Ehcache配置文件,那么EhCacheCacheManager将自动作为缓存的实现。因此,在resources目录下创建ehcache.xml文件作为Ehcache缓存的配置文件,代码如下:

<config
        xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
        xmlns='http://www.ehcache.org/v3'
        xsi:schemaLocation="http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core.xsd">

    <!-- 声明的Cache别名foo-->
    <cache alias="foo">
        <!-- 声明缓存的键和值的type为String,如果未指定,则默认值为java.lang.Object-->
        <key-type>java.lang.String</key-type>
        <value-type>java.lang.String</value-type>
        <expiry>
            <ttl unit="minutes">2</ttl>
        </expiry>
        <!-- 分配资源大小-->
        <resources>
            <!-- 缓存在堆上最多容纳2000条-->
            <heap unit="entries">2000</heap>
            <!-- 以及开始驱逐之前最多500MB的堆外内存-->
            <offheap unit="MB">500</offheap>
        </resources>
    </cache>

    <!-- <cache-template>元素使您可以创建抽象配置,<cache>然后进一步的配置可以“扩展”-->
    <cache-template name="myDefaults">
        <key-type>java.lang.Long</key-type>
        <value-type>java.lang.String</value-type>
        <heap unit="entries">200</heap>
    </cache-template>

    <!-- 声明Cache的别名为bar,bar使用<cache-template>的名称为myDefaults并将其覆盖key-type为Number类型。 -->
    <cache alias="bar" uses-template="myDefaults">
        <key-type>java.lang.Number</key-type>
    </cache>

    <!-- 声明Cache的别名为simpleCache,它仅使用myDefaults配置CacheConfiguration -->
    <cache alias="simpleCache" uses-template="myDefaults" />

    <cache-template name="bookTemplate">
        <key-type>java.lang.String</key-type>
        <value-type>com.demo.chapter091.entity.Book</value-type>
        <heap unit="entries">200</heap>
    </cache-template>

    <cache alias="book_cache" uses-template="bookTemplate">
        <expiry>
            <ttl unit="minutes">1</ttl>
        </expiry>
    </cache>



</config>

具有107扩展名的XML:

<ehcache:config
        xmlns:ehcache="http://www.ehcache.org/v3"
        xmlns:jcache="http://www.ehcache.org/v3/jsr107">

    <!--
      OPTIONAL
       由CacheManager管理和生命周期化的服务
    -->
    <ehcache:service>
        <!--
          另一个命名空间中的一个元素,这里以我们的JSR-107扩展为例
        -->
        <jcache:defaults>
            <jcache:cache name="invoices" template="myDefaultTemplate"/>
        </jcache:defaults>
    </ehcache:service>

    <!--
      OPTIONAL
        <cache>元素定义由强制'alias'属性标识的缓存,由CacheManager管理
    -->
    <ehcache:cache alias="productCache">

        <!--
          OPTIONAL, defaults to java.lang.Object
            The FQCN of the type of keys K we'll use with the Cache<K, V>
        -->
        <ehcache:key-type copier="org.ehcache.impl.copy.SerializingCopier">java.lang.Long</ehcache:key-type>

        <!--
          OPTIONAL, defaults to java.lang.Object
            The FQCN of the type of values V we'll use with the Cache<K, V>
        -->
        <ehcache:value-type copier="org.ehcache.impl.copy.SerializingCopier">com.pany.domain.Product</ehcache:value-type>

        <!--
          OPTIONAL, defaults to no expiry
            可以使缓存条目在给定时间后过期
        -->
        <ehcache:expiry>
            <!--
              time to idle<tti>空闲时间,使条目保持不变的最大时间可以使缓存条目在给定时间后到期,其他选项包括:
              <ttl>,生存时间;
              <class>,用于自定义Expiry实现;
              <无>,无有效期
            -->
            <ehcache:tti unit="minutes">2</ehcache:tti>
        </ehcache:expiry>

        <!--
          OPTIONAL, defaults to no advice
            驱逐顾问,使您可以控制哪些条目仅应作为org.ehcache.config.EvictionAdvisor实现的最后手段FQCN驱逐
        -->
        <ehcache:eviction-advisor>com.pany.ehcache.MyEvictionAdvisor</ehcache:eviction-advisor>

        <!--
          OPTIONAL,
            Let's you configure your cache as a "cache-through",
            i.e. a Cache that uses a CacheLoaderWriter to load on misses, and write on mutative operations.
            让我们将缓存配置为“直通式缓存”,即使用CacheLoaderWriter的缓存加载未命中的内容,并写入变异操作。
        -->
        <ehcache:loader-writer>
            <!--
                The FQCN implementing org.ehcache.spi.loaderwriter.CacheLoaderWriter
            -->
            <ehcache:class>com.pany.ehcache.integration.ProductCacheLoaderWriter</ehcache:class>
            <!-- Any further elements in another namespace -->
        </ehcache:loader-writer>

        <!--
            逐出之前,要保留在缓存中的最大条目数
        -->
        <ehcache:heap unit="entries">200</ehcache:heap>

        <!--
           OPTIONAL
            Any further elements in another namespace
        -->
    </ehcache:cache>

    <!--
      OPTIONAL
        A <cache-template> defines a named template that can be used be <cache> definitions in this same file
        They have all the same property as the <cache> elements above
    -->
    <ehcache:cache-template name="myDefaultTemplate">
        <ehcache:expiry>
            <ehcache:none/>
        </ehcache:expiry>
        <!--
           OPTIONAL
            Any further elements in another namespace
        -->
    </ehcache:cache-template>

    <!--
      通过在uses-template属性中引用高速缓存模板的名称来使用上述模板的<cache>:
    -->
    <ehcache:cache alias="customerCache" uses-template="myDefaultTemplate">
        <!--
          Adds the key and value type configuration
        -->
        <ehcache:key-type>java.lang.Long</ehcache:key-type>
        <ehcache:value-type>com.pany.domain.Customer</ehcache:value-type>

        <!--
          Overwrites the capacity limit set by the template to a new value
        -->
        <ehcache:heap unit="entries">200</ehcache:heap>
    </ehcache:cache>

</ehcache:config>

另外,如果开发者想自定义Ehcache配置文件的位置,可在application.yml中添加如下配置:

spring:
  cache:
    jcache:
      config: ehcache.xml

3. 开启缓存

在项目的入口类上添加@EnableCaching注解开启缓存,代码如下:

@SpringBootApplication
@EnableCaching
public class Chapter091Application {

    public static void main(String[] args) {
        SpringApplication.run(Chapter091Application.class, args);
    }

}

4. 创建BookDao

创建Book实体类和BookDao,代码如下

@Repository
@CacheConfig(cacheNames = "book_cache")
public class BookDao {

    @Cacheable
    public Book getBookById(Integer id){
        System.out.println("----getBookById");
        Book book = new Book();
        book.setId(id);
        book.setName("三国演义");
        book.setAuthor("罗贯中");
        return book;
    }

    @CachePut(key = "#book.id")
    public Book updateBookById(Book book){
        System.out.println("----updateBookById");
        book.setName("三国演义2");
        return book;
    }

    @CacheEvict(key = "#id")
    public void deleteBookById(Integer id){
        System.out.println("-----deleteBookById");
    }

}


@Data
public class Book implements Serializable {

    private Integer id;
    private String name;
    private String author;
}

  • 在BookDao上添加@CacheConfig注解指明使用缓存的名字,这个配置可选,若不使用@CacheConfig注解,则直接在@Cacheable注解中指明缓存的名字。

  • 在getBookById方法上添加@Cacheable注解表示对该方法进行缓存,默认情况下缓存的key是方法的参数,缓存的值是方法的返回值。当开发者在其他类中调用该方法时,首先会根据参数查看缓存中是否有相关的数据,若有则直接使用缓存的数据,该方法不会执行,否者执行该方法,执行成功后将返回值缓存起来,但若在当前类中调用该方法,则缓存不会生效。

  • @Cacheable注解中还有一个属性condition用来藐视缓存执行的时机,例如@Cacheable(conditioin="#id%2==0")表示当id对2取模为0时才进行缓存,否则不执行缓存。

  • 如果开发者不想使用默认的key,第15行表示缓存的key为book参数中id的值,第22行表示缓存的key为参数id。错了这种用参数定义key之外,Spring还提供了一个root对象用来生成key,如下图所示:

    属性名称属性描述用法实例
    methodName当前方法名#root.methodName
    method当前方法对象#root.method.name
    caches当前方法使用的缓存#root.caches[0].name
    target当前被调用的对象#root.target
    targetClass当前被调用对象的Class#root.targetClass
    args当前方法参数数组#root.args[0]
  • 如果这些key不能够瞒住开发需求,开发者也可以自定义缓存key的生成器KeyGenerator,代码如下:

    @Component
    public class MyKeyGenerator implements KeyGenerator {
        @Override
        public Object generate(Object o, Method method, Object... objects) {
            return Arrays.toString(objects);
        }
    }
    
    
    
    
    @Service
    @CacheConfig(cacheNames = "book_cache")
    public class BookService {
    
        @Autowired
        MyKeyGenerator myKeyGenerator;
    
        @Cacheable(keyGenerator = "myKeyGenerator")
        public Book getBookById(Integer id){
            System.out.println("----getBookById");
            Book book = new Book();
            book.setId(id);
            book.setName("三国演义");
            book.setAuthor("罗贯中");
            return book;
        }
    }
    
    
  • 自定义MyKeyGenerator实现KeyGenerator接口,然后实现generate方法,该方法的三个参数分别是当前对象,当前请求方法以及方法的参数,开发者可以根据这些信息组成一个新的key返回,返回值就是缓存的key在第19行@Cacheable中引用MyKeyGenerator实例即可;

  • @CachePut注解一般用于跟新方法上,与@Cacheable不同,添加了@CachePut注解每次在执行时都不回去检查缓存中是否有数据,而是直接执行方法,然后将方法执行的结果缓存起来,如果key对应数据已经被缓存起来了,就会覆盖之前的数据,这样就可以避免再次加载数据时获取到脏数据。同时@CachePut具有和@Cacheable类似的属性这里不再赘述。

  • @CacheEvict一般用于删除方法上,表示移除一个key对应的缓存数据,@CacheEvict注解有两个特殊性的属性:allEntries和beforeInvocation表示是否在方法执行前移除缓存中的数据,默认为false,即在方法执行后移除缓存中数据。

5. 创建测试类

创建测试类,代码如下:

@SpringBootTest
class BookDaoTest {

    @Autowired
    BookDao bookDao;

    @Test
    public void contextLoads(){
        bookDao.getBookById(1);
        bookDao.getBookById(1);
        bookDao.deleteBookById(1);
        Book book3 = bookDao.getBookById(1);
        System.out.println("book3 " + book3);
        Book book = new Book();
        book.setName("三国演义");
        book.setAuthor("罗贯中");
        book.setId(1);

        bookDao.updateBookById(book);
        Book book4 = bookDao.getBookById(1);
        System.out.println("boo4 " + book4);

    }

}

执行测试方法控制台打印数据如下:
在这里插入图片描述

备注:更多相关配置请参考Ehcache 3.8文档

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值