阿里P7架构师分享:15分钟快速掌握SpringCache(使用详解)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了阿里P7架构师分享:15分钟快速掌握SpringCache(使用详解)相关的知识,希望对你有一定的参考价值。

缓存的策略有很多,在应用系统中可根据情况 选择,通常会把一些 静态数据后者变化频率不高的数据放到缓存中,如配置参数、字典表等。而有些场景可能要寻找替代方案,比如,想提升全文检索的速度,在复杂场景下建议使用搜索引擎,如Solr或 ElasticSearch。

通常在Web开发中,不同层级对应的缓存要求和缓存策略全然不同,如下图:
技术图片
下面了解一下缓存中的两个比较重要的基本概念:

1. 缓存命中率

即从缓存中读取数据的次数与总读取次数的比率。一般来说,命中率越高越好。

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

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

如果要做缓存,就一定要监控这个指标,来看缓存是否工作良好。

2.过期策略

  • FIFO(First In First Out):先进先出策略。
  • LRU(Least Recently Used): 最久未使用策略,即一定时间段内使用率最少的那个数据被溢出。
  • TTL(Time to Live): 存活期,即从缓存中创建时间点开始直至到期的一个时间段。
  • TTI(Time To Idle): 空闲期,即一个 数据多久没被访问就从缓存中移除的时间。
    自定义实现一个缓存管理器:

首先自定义一个User实体类。

public class User implements Serializable {
    private String userId;
    private String userName;
    private int age;

    public User(String userId) {
        this.userId = userId;
    }

    public String getUserId() {
        return userId;
    }

    public void setUserId(String userId) {
        this.userId = userId;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

}

接下来定义一个缓存管理器:

public class CacheManager<T> {
    private Map<String, T> cache = new ConcurrentHashMap<String, T>();

    public T getValue(Object key) {
        return cache.get(key);
    }

    public void addOrUpdate(String key, T value) {
        cache.put(key, value);
    }

    public void delCache(String key) {
        if (cache.containsKey(key)) {
            cache.remove(key);
        }
    }

    public void clearCache() {
        cache.clear();
    }
}

提供用户查询的服务类,此服务类使用缓存管理器来支持用户查询。

public class UserService {

    private CacheManager<User> cacheManager;

    public UserService() {
        cacheManager = new CacheManager<User>();
    }

    @Cacheable(cacheNames = "users")
    public User getUserById(String userId) {
        // 方法内部实现不考虑缓存逻辑,直接实现业务
        System.out.println("read quert user. " + userId);
        return getFromDB(userId);
    }

    public void reload() {
        cacheManager.clearCache();
    }

    private User getFromDB(String userId) {
        return new User(userId);
    }

}

使用SpringCache 来实现上面的例子:

public class UserServiceUseSpringCache {

    private CacheManager<User> cacheManager;

    public UserServiceUseSpringCache() {
        cacheManager = new CacheManager<User>();
    }

    public User getUserById(String userId) {
        User result = cacheManager.getValue(userId);
        if (result != null) {
            System.out.println("get from cache..." + userId);
            // 如果在缓存中,则直接返回缓存的结果
            return result;
        }

        // 否则从数据库查询
        result = getFromDB(userId);
        if (result != null) {
            // 将数据库查询的结果更新到缓存中
            cacheManager.addOrUpdate(userId, result);
        }
        return result;

    }

    public void reload() {
        cacheManager.clearCache();
    }

    private User getFromDB(String userId) {
        return new User(userId);
    }

}

现在还需要一个Spring 配置文件来支持基于注解的缓存:

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:cache="http://www.springframework.org/schema/cache"
 xmlns:p="http://www.springframework.org/schema/p"
 xsi:schemaLocation="http://www.springframework.org/schema/beans 
 http://www.springframework.org/schema/beans/spring-beans.xsd 
 http://www.springframework.org/schema/cache 
 http://www.springframework.org/schema/cache/spring-cache.xsd"> 

 <!-- 启动基于注解的缓存驱动 这个配置项默认使用了一个定义为cacheManager的缓存管理器。 -->
 <cache:annotation-driven />

 <bean id="accountServiceBean" class="cacheOfAnno.AccountService"/> 

 <!-- generic cache manager -->
 <bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
 <property name="caches"> 
 <set> 
 <bean
 class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="default" /> 

 <bean
 class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="users" /> 
 </set> 
 </property> 
 </bean> 
</beans>

上面在UserService代码中没有看到任何缓存逻辑代码,只需一个注解@Cacheable(cacheNames="users"),就实现了基本的缓存方案,代码变得非常优雅、简洁。使用Spring Cache 只需完成以下两个步骤:

  • 缓存定义: 确定需要缓存的方法和缓存策略
  • 缓存配置: 配置缓存

以上是关于阿里P7架构师分享:15分钟快速掌握SpringCache(使用详解)的主要内容,如果未能解决你的问题,请参考以下文章

奈学教育《P7架构师》课程大纲

奈学教育《P7架构师》课程大纲

怎样的架构设计能力,才能成功拿下阿里P7?

阿里P5到阿里P7架构师,离不开这一份深入浅出JVM教程PDF文档

阿里P5到阿里P7架构师,离不开这一份深入浅出JVM教程PDF文档

总结 480 页,超 30W 字 2021 最新一线大厂 Java 高级架构师面试题,已拿阿里 P7+ 意向书!