Spring Cache抽象详解

编程技术  /  houtizong 发布于 3年前   83

缓存简介

缓存,我的理解是:让数据更接近于使用者;工作机制是:先从缓存中读取数据,如果没有再从慢速设备上读取实际数据(数据也会存入缓存);缓存什么:那些经常读取且不经常修改的数据/那些昂贵(CPU/IO)的且对于相同的请求有相同的计算结果的数据。如CPU--L1/L2--内存--磁盘就是一个典型的例子,CPU需要数据时先从L1/L2中读取,如果没有到内存中找,如果还没有会到磁盘上找。还有如用过Maven的朋友都应该知道,我们找依赖的时候,先从本机仓库找,再从本地服务器仓库找,最后到远程仓库服务器找;还有如京东的物流为什么那么快?他们在各个地都有分仓库,如果该仓库有货物那么送货的速度是非常快的。

 

缓存命中率

即从缓存中读取数据的次数 与 总读取次数的比率,命中率越高越好:

命中率 = 从缓存中读取次数 / (总读取次数[从缓存中读取次数 + 从慢速设备上读取的次数])

Miss率 = 没有从缓存中读取的次数 / (总读取次数[从缓存中读取次数 + 从慢速设备上读取的次数])

 

这是一个非常重要的监控指标,如果做缓存一定要健康这个指标来看缓存是否工作良好;

 

缓存策略

Eviction policy

移除策略,即如果缓存满了,从缓存中移除数据的策略;常见的有LFU、LRU、FIFO:

FIFO(First In First Out):先进先出算法,即先放入缓存的先被移除;

LRU(Least Recently Used):最久未使用算法,使用时间距离现在最久的那个被移除;

LFU(Least Frequently Used):最近最少使用算法,一定时间段内使用次数(频率)最少的那个被移除;

 

TTL(Time To Live )

存活期,即从缓存中创建时间点开始直到它到期的一个时间段(不管在这个时间段内有没有访问都将过期)

 

TTI(Time To Idle)

空闲期,即一个数据多久没被访问将从缓存中移除的时间。

 

 

到此,基本了解了缓存的知识,在Java中,我们一般对调用方法进行缓存控制,比如我调用"findUserById(Long id)",那么我应该在调用这个方法之前先从缓存中查找有没有,如果没有再掉该方法如从数据库加载用户,然后添加到缓存中,下次调用时将会从缓存中获取到数据。

 

自Spring 3.1起,提供了类似于@Transactional注解事务的注解Cache支持,且提供了Cache抽象;在此之前一般通过AOP实现;使用Spring Cache的好处:

提供基本的Cache抽象,方便切换各种底层Cache;

通过注解Cache可以实现类似于事务一样,缓存逻辑透明的应用到我们的业务代码上,且只需要更少的代码就可以完成;

提供事务回滚时也自动回滚缓存;

支持比较复杂的缓存逻辑;

 

对于Spring Cache抽象,主要从以下几个方面学习:

  • Cache API及默认提供的实现
  • Cache注解
  • 实现复杂的Cache逻辑

 

Cache API及默认提供的实现

Spring提供的核心Cache接口: 

package org.springframework.cache;public interface Cache {String getName();  //缓存的名字Object getNativeCache(); //得到底层使用的缓存,如EhcacheValueWrapper get(Object key); //根据key得到一个ValueWrapper,然后调用其get方法获取值<T> T get(Object key, Class<T> type);//根据key,和value的类型直接获取valuevoid put(Object key, Object value);//往缓存放数据void evict(Object key);//从缓存中移除key对应的缓存void clear(); //清空缓存interface ValueWrapper { //缓存值的WrapperObject get(); //得到真实的value        }}

提供了缓存操作的读取/写入/移除方法;

 

 

默认提供了如下实现:

ConcurrentMapCache:使用java.util.concurrent.ConcurrentHashMap实现的Cache;

GuavaCache:对Guava com.google.common.cache.Cache进行的Wrapper,需要Google Guava 12.0或更高版本,@since spring 4;

EhCacheCache:使用Ehcache实现

JCacheCache:对javax.cache.Cache进行的wrapper,@since spring 3.2;spring4将此类更新到JCache 0.11版本;

 

另外,因为我们在应用中并不是使用一个Cache,而是多个,因此Spring还提供了CacheManager抽象,用于缓存的管理: 

package org.springframework.cache;import java.util.Collection;public interface CacheManager {Cache getCache(String name); //根据Cache名字获取Cache Collection<String> getCacheNames(); //得到所有Cache的名字}

 

默认提供的实现: 

ConcurrentMapCacheManager/ConcurrentMapCacheFactoryBean:管理ConcurrentMapCache;

GuavaCacheManager;

EhCacheCacheManager/EhCacheManagerFactoryBean;

JCacheCacheManager/JCacheManagerFactoryBean;

 

另外还提供了CompositeCacheManager用于组合CacheManager,即可以从多个CacheManager中轮询得到相应的Cache,如

<bean id="cacheManager" class="org.springframework.cache.support.CompositeCacheManager">    <property name="cacheManagers">        <list>            <ref bean="ehcacheManager"/>            <ref bean="jcacheManager"/>        </list>    </property>    <property name="fallbackToNoOpCache" value="true"/></bean>

当我们调用cacheManager.getCache(cacheName) 时,会先从第一个cacheManager中查找有没有cacheName的cache,如果没有接着查找第二个,如果最后找不到,因为fallbackToNoOpCache=true,那么将返回一个NOP的Cache否则返回null。

 

 

除了GuavaCacheManager之外,其他Cache都支持Spring事务的,即如果事务回滚了,Cache的数据也会移除掉。

 

Spring不进行Cache的缓存策略的维护,这些都是由底层Cache自己实现,Spring只是提供了一个Wrapper,提供一套对外一致的API。

 

示例

需要添加Ehcache依赖,具体依赖轻参考pom.xml

 

SpringCacheTest.java

    @Test    public void test() throws IOException {        //创建底层Cache        net.sf.ehcache.CacheManager ehcacheManager                = new net.sf.ehcache.CacheManager(new ClassPathResource("ehcache.xml").getInputStream());        //创建Spring的CacheManager        EhCacheCacheManager cacheCacheManager = new EhCacheCacheManager();        //设置底层的CacheManager        cacheCacheManager.setCacheManager(ehcacheManager);        Long id = 1L;        User user = new User(id, "zhang", "[email protected]");        //根据缓存名字获取Cache        Cache cache = cacheCacheManager.getCache("user");        //往缓存写数据        cache.put(id, user);        //从缓存读数据        Assert.assertNotNull(cache.get(id, User.class));    }

此处直接使用Spring提供的API进行操作;我们也可以通过xml/注解方式配置到spring容器;

 

xml风格的(spring-cache.xml):

    <bean id="ehcacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">        <property name="configLocation" value="classpath:ehcache.xml"/>    </bean>    <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">        <property name="cacheManager" ref="ehcacheManager"/>        <property name="transactionAware" value="true"/>    </bean>

spring提供EhCacheManagerFactoryBean来简化ehcache cacheManager的创建,这样注入configLocation,会自动根据路径从classpath下找,比编码方式简单多了,然后就可以从spring容器获取cacheManager进行操作了。此处的transactionAware表示是否事务环绕的,如果true,则如果事务回滚,缓存也回滚,默认false。

 

 

注解风格的(AppConfig.java):

    @Bean    public CacheManager cacheManager() {        try {            net.sf.ehcache.CacheManager ehcacheCacheManager                    = new net.sf.ehcache.CacheManager(new ClassPathResource("ehcache.xml").getInputStream());            EhCacheCacheManager cacheCacheManager = new EhCacheCacheManager(ehcacheCacheManager);            return cacheCacheManager;        } catch (IOException e) {            throw new RuntimeException(e);        }    }

和编程方式差不多就不多介绍了。

请勿发布不友善或者负能量的内容。与人为善,比聪明更重要!

留言需要登陆哦

技术博客集 - 网站简介:
前后端技术:
后端基于Hyperf2.1框架开发,前端使用Bootstrap可视化布局系统生成

网站主要作用:
1.编程技术分享及讨论交流,内置聊天系统;
2.测试交流框架问题,比如:Hyperf、Laravel、TP、beego;
3.本站数据是基于大数据采集等爬虫技术为基础助力分享知识,如有侵权请发邮件到站长邮箱,站长会尽快处理;
4.站长邮箱:[email protected];

      订阅博客周刊 去订阅

文章归档

文章标签

友情链接

Auther ·HouTiZong
侯体宗的博客
© 2020 zongscan.com
版权所有ICP证 : 粤ICP备20027696号
PHP交流群 也可以扫右边的二维码
侯体宗的博客