Spring中使用ehcache缓存的方法及原理详解

 更新时间:2024年01月10日 10:20:46   作者:爱coding的同学  
这篇文章主要介绍了Spring中使用ehcache缓存的方法及原理详解,ehcache具有很强的灵活性,提供了LRU、LFU和FIFO缓存淘汰算法,Ehcache 1.2引入了最近最少使用、最久未使用和先进先 出缓存淘汰算法, 构成了完整的缓存淘汰算法,,需要的朋友可以参考下

ehcache简介

为什么使用ehcache

(1)速度快。

(2)轻量,很小的jar包,Ehcache 2.2.3才668kb。

(3)和spring集成,通过注解就可以实现本地缓存,使用简单。

(4)具有很强的灵活性,提供了LRU、LFU和FIFO缓存淘汰算法,Ehcache 1.2引入了最近最少使用、最久未使用和先进先 出缓存淘汰算法, 构成了完整的缓存淘汰算法。

(5)提供内存和磁盘存储,Ehcache和大多数缓存解决方案一样,提供高性能的内存和磁盘存储。在VM重启后,持久化到 磁盘的存储可以复原数据。

使用案例

配置

pom.xml中添加ehcache依赖包

        <dependency>
            <groupId>net.sf.ehcache</groupId>
            <artifactId>ehcache</artifactId>
            <version>2.9.1</version>
        </dependency>

ehcache文件配置:

<?xml version="1.0" encoding="UTF-8"?>
<ehcache updateCheck="false">
<diskStore path="java.io.tmpdir" />
<!-- name:缓存名称。 
maxElementsInMemory:缓存最大个数。 
eternal:对象是否永久有效,一但设置了,
timeout将不起作用。 
timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。 仅当eternal=false对象
不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。 
timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和
失效时间之间。 仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。 
overflowToDisk:当内存中对象数量达到maxElementsInMemory时,Ehcache将会对象写到磁盘中。 
diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。
每个Cache都应该有自己的一个缓冲区。 
maxElementsOnDisk:硬盘最大缓存个数。 
diskPersistent:是否缓存虚拟机重启期数据 Whether the disk 
store persists between restarts of the Virtual Machine. The default value 
is false. 
diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的
策略去清理内存。 
默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。 
clearOnFlush:内存数量最大时是否清除。 -->
<defaultCache maxElementsInMemory="10000" eternal="false"
timeToIdleSeconds="60" timeToLiveSeconds="60" overflowToDisk="true"
maxElementsOnDisk="10000000" diskPersistent="false"
diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU" />


<cache name="applicationCache" maxElementsInMemory="10000"
eternal="false" timeToIdleSeconds="150" timeToLiveSeconds="600"
overflowToDisk="false" diskPersistent="false"
diskExpiryThreadIntervalSeconds="1" />


<cache name="indexCache" maxElementsInMemory="10000"
eternal="false" timeToIdleSeconds="60" timeToLiveSeconds="600"
overflowToDisk="false" diskPersistent="false"
diskExpiryThreadIntervalSeconds="1" />

</ehcache>

spring文件中的配置

<cache:annotation-driven cache-manager="ehcacheManager"/> 

<!-- cacheManager工厂类,指定ehcache.xml的位置 -->
<beans:bean id="ehcacheManagerFactory"
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<beans:property name="configLocation" value="classpath:config/ehcache.xml" />
</beans:bean>

<!-- 声明cacheManager -->
<beans:bean id="ehcacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
<beans:property name="cacheManager" ref="ehcacheManagerFactory" />
<beans:property name="transactionAware" value="true" />
</beans:bean>

此处的transactionAware表示是否事务环绕的,如果值是true,则如果事务回滚,缓存也回滚,默认false。

项目中的使用

例子,通过简单的配置即可实现缓存效果

    @Override
    @Cacheable("applicationCache")
    public Map<String, Object> getAppDetailById(long appId) {
        byte[] app = redisTemplate.getRaw(String.format(CacheKeys.APP_DETAIL_BY_ID, appId));
        if (null == app) {
            return Collections.EMPTY_MAP;
        }
        try {
            return CompressUtil.deCompress(app, appId);
        } catch (IOException t) {
            throw new FlymeTVServiceException(Errors.ServiceErrors.DE_COMPRESS_ERROR,
                    new Object[] { "appId:" + appId });
        }
    }
    @Cacheable(value = "categoryCache", key = "#categoryId + #sortType + #start + #max")
    @Override
    public MultiPage<Map<String, Object>> getCategoryApps(int categoryId, int sortType, 
int start, int max) {
        MultiPage<Map<String, Object>> result = new MultiPage<Map<String, Object>>();
        String key = String.format(CacheKeys.CATEGORY_APPS, categoryId, sortType);
        List<String> appIds = redisTemplate.lrange(key, start, max + BACKUP_APP_SIZE);
        .....
        return result;
    }

注解接口介绍如下:

   public @interface Cacheable {  
            //缓存的名字,可以把数据写到多个缓存
    String[] value();          
     //缓存key,如果不指定将使用默认的KeyGenerator生成
    String key() default "";    
    //满足缓存条件的数据才会放入缓存,condition在调用方法之前和之后都会判断  
    String condition() default "";
     //用于否决缓存更新的,不像condition,该表达只在方法执行之后判断,此时可以拿到返回值result进行判断了
    String unless() default "";    
   }

例子,java代码如下

@Cacheable(value = "user", key = "#id", condition = "#id lt 10")  
public User conditionFindById(final Long id) 

根据运行流程,如下@Cacheable将在执行方法之前( #result还拿不到返回值)判断condition,如果返回true,则查缓存。

Key生成器

如果在Cache注解上没有指定key的话@Cacheable(“applicationCache”),会使用KeyGenerator进行生成一个key: java代码

public interface KeyGenerator {  
    Object generate(Object target, Method method, Object... params);  
}  

默认提供了DefaultKeyGenerator生成器

  public Object generate(Object target, Method method, Object[] params)
  {
    if (params.length == 1) {
      return params[0] == null ? Integer.valueOf(53) : params[0];
    }
    if (params.length == 0) {
      return Integer.valueOf(0);
    }
    int hashCode = 17;
    for (Object object : params) {
      hashCode = 31 * hashCode + (object == null ? 53 : object.hashCode());
    }
    return Integer.valueOf(hashCode);
  }

新增和删除注解

@CachePut 应用到写数据的方法上,如新增/修改方法,调用方法时会自动把相应的数据放入缓存: java代码

@CachePut(value = "user", key = "#user.id")  
public User save(User user) {  
    users.add(user);  
    return user;  
}  

即调用该方法时,会把user.id作为key,返回值作为value放入缓存; 接口介绍,java代码:

public @interface CachePut {  
    //缓存的名字,可以把数据写到多个缓存
    String[] value();     
    //缓存key,如果不指定将使用默认的KeyGenerator生成 
    String key() default "";     
    //满足缓存条件的数据才会放入缓存,condition在调用方法之前和之后都会判断  
    String condition() default ""; 
     //用于否决缓存更新的,不像condition,该表达只在方法执行之后判断,此时可以拿到返回值result进行判断了
    String unless() default "";     
} 

例子,java代码

@CachePut(value = "user", key = "#user.id", unless = "#result.username eq 'zhang'")  
public User conditionSave2(final User user) 

根据运行流程,如下@CachePut将在执行完方法后(#result就能拿到返回值了)判断unless,如果返回false,则放入缓存;(即跟condition相反)

到此这篇关于Spring中使用ehcache缓存的方法及原理详解的文章就介绍到这了,更多相关Spring使用ehcache缓存内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • java使用spring实现读写分离的示例代码

    java使用spring实现读写分离的示例代码

    本篇文章主要介绍了java使用spring实现读写分离的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-12-12
  • 如何基于java语言实现八皇后问题

    如何基于java语言实现八皇后问题

    这篇文章主要介绍了如何基于java语言实现八皇后问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-12-12
  • IDEA配置码云Gitee的使用详解

    IDEA配置码云Gitee的使用详解

    这篇文章主要介绍了IDEA配置码云Gitee的使用,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-12-12
  • Java Socket编程实例(三)- TCP服务端线程池

    Java Socket编程实例(三)- TCP服务端线程池

    这篇文章主要讲解Java Socket编程中TCP服务端线程池的实例,希望能给大家做一个参考。
    2016-06-06
  • SpringBoot使用@PostConstruct注解导入配置方式

    SpringBoot使用@PostConstruct注解导入配置方式

    这篇文章主要介绍了SpringBoot使用@PostConstruct注解导入配置方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-11-11
  • SpringBoot 策略模式实现切换上传文件模式

    SpringBoot 策略模式实现切换上传文件模式

    策略模式是指有一定行动内容的相对稳定的策略名称,这篇文章主要介绍了SpringBoot 策略模式 切换上传文件模式,需要的朋友可以参考下
    2023-11-11
  • 基于Idea+Jconsole实现线程监控步骤

    基于Idea+Jconsole实现线程监控步骤

    这篇文章主要介绍了基于Idea+Jconsole实现线程监控功能,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-04-04
  • Mybatis-Plus如何实现时间日期的比较

    Mybatis-Plus如何实现时间日期的比较

    文章主要讨论了在使用Mybatis-Plus进行数据库查询时,如何正确处理日期和时间的比较,作者强调了使用数据库函数进行比较的重要性,避免了直接将时间转换为字符串进行比较的错误,同时,作者建议在需要比较天数时使用LocalDate
    2024-11-11
  • 使用SpringBoot发送邮件的方法详解

    使用SpringBoot发送邮件的方法详解

    这篇文章主要介绍了使用SpringBoot发送邮件的方法详解,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2023-05-05
  • Java Socket实现单线程通信的方法示例

    Java Socket实现单线程通信的方法示例

    这篇文章主要介绍了Java Socket实现单线程通信的方法,结合具体实例形式分析了java socket单线程通信的原理与客户端、服务器端相关实现技巧,需要的朋友可以参考下
    2017-06-06

最新评论