缓存的基本概念
通常在 Web 应用发开中,不同层级对应的缓存策略和要求是不一样的,如下:
以下是缓存中的2个比较重要的基本概念:
- 缓存命中率
缓存命中率即从缓存中读取数据的次数和总读取次数的比例,一般来说,命中率越高越好:命中率 = 从缓存中读取的次数 / 总读取次数Miss 率 = 没有从缓存中读取的次数 / 总读取次数※总读取次数 = 从缓存中读取的次数 + 从慢速设备中读取的次数
- 缓存过期策略
如果缓存满了,缓存中移除数据的策略,常见的策略有: LFU、LRU、FIFO 等;
-
- FIFO(First In First Out):先进先出策略,先放入缓存的数据先被移除;
- LRU(Least Recently Used):最久未使用策略,使用距离现在最久的那个数据被移除;
- LFU(Least Frequently Used):最近最少使用策略,一定时间内使用次数最少的那个数据被移除;
-
- TTL(Time To Live):固定存活期策略,从缓存中创建时间点开始直到到期的一个时间段,不管在该时间是否被访问否将过期;
- TTI(Time To Idle):固定空闲期策略,一个数据在指定的时间内没有被访问,就会从缓存中被移除;
Spring 4.0 开始全面支持 JSR-107(JCache API),提供了一种可以在方法级别进行缓存的缓存抽象,主要的实现过程是在缓存注解类中进行相关方法的标记,Spring 通过 AOP 功能为其生成具有缓存功能的代理类;
使用 Spring Cache 时有以下几点要注意:
- Spring Cache 提供的仅仅是一种抽象,而没有提供具体实现,所以一般会自己使用 AOP 来进行一定程度的封装实现(或者使用第三方的缓存框架);
- Spring Cache 并不针对多进程的应用环境进行专门的处理,即当应用程序处于分布式或集群环境下时,需要针对具体的缓存进行相应的配置;
- Spring Cache 抽象的操作中并没有锁的概念,当多线程并发操作同一个缓存项时,将可能得到过期的数据,此时可以自己实现或借助第三方缓存框架来实现并发锁;
Spring Cache 缓存处理
一个简单的使用示例
Spring Cache 的基本使用主要包括以下2个步骤:
- 定义缓存:确定需要缓存的方法和缓存策略;
- 缓存配置:配置缓存信息;
在业务层对象 UserService 使用注解标注缓存行为:
package site.assad.service;
public class UserService {
private UserDao userDao;
private final static Logger log = LogManager.getLogger();
//标记方式使用缓存,当调用该方法时,会先从 users 缓存中匹配查询缓存对象,如果匹配则直接返回缓存对象,否则执行方法内的逻辑
//在这个方法中,对应浑春的 key 为 userId 的值,value 为 userId 对应的 User 对象;
cacheNames = "users") (
public User getUser(final int userid){
log.debug("real query user from DB");
//不考虑缓存逻辑,直接实现业务
User user = null;
user = userDao.getUserById(userid);
return user;
}
}
在Spring上下文配置文件 applicationContext.xml 中配置 Spring Cache:
<!--Spring Cache 配置-->
<!--启动基于注解的缓存驱动,该驱动会默认使用一个定义为“cacheManager”的缓存管理器-->
<cache:annotation-driven />
<!--指定使用缓存注解的类,多个类可以使用内嵌的list节点包含-->
<bean id="accountServiceBean" class="site.assad.service.UserService" />
<!--配置缓存管理器,使用默认实现SimpleCacheManager-->
<bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
<property name="caches">
<list>
<bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="default" />
<bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="users" />
</list>
</property>
</bean>
缓存注解
Spring 4.X 定义了4个可在方法级别、1个类级别上使用的注解,用于定义在某方法上的返回值会被缓存、或者从缓存中移除;
@Cacheable
这两个注解用于定制被注解的方法的返回值是可以被缓存的,工作原理是 Spring 首先从缓存中查找数据,如果没有则执行方法并缓存结果&