阿里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 只需完成以下两个步骤:

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

原文地址:https://blog.51cto.com/14541438/2438615

时间: 2024-11-08 08:56:09

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

阿里P7架构师:通往架构师路上的经验总结

困扰架构师日常问题 架构师应不应该写代码为什么别人的系统总是那么烂成为架构师最困难的门槛是什么?如何更高效的学习?面对目前流行的技术不知如何下手?一家公司待久了,过得很安逸,但跳槽时面试碰壁?觉得现在的技术基础感觉到很扎实,但就是自己的技术提升不上?觉得自己很牛B,一般需求都能搞定,但是所学的知识点没有系统化,很难在技术领域继续突破?现在觉得自己技术还可以,但就是薪资涨不上去? 以上这几点,做为开发人员的你们,有遇到过么?有为自己想过么?有细心仔细的去解决过这些问题么?有深刻的想过么?虽然这几个

阿里P7架构师告诉你Java架构师必须知道的 6 大设计原则

在软件开发中,前人对软件系统的设计和开发总结了一些原则和模式, 不管用什么语言做开发,都将对我们系统设计和开发提供指导意义.本文主要将总结这些常见的原则,和具体阐述意义. 开发原则 面向对象的基本原则(solid)是五个,但是在经常被提到的除了这五个之外还有 迪米特法则和合成复用原则等, 所以在常见的文章中有表示写六大或七大原则的: 除此之外我还将给出一些其它相关书籍和互联网上出现的原则: S单一职责SRP Single-Responsibility Principle, 一个类,最好只做一件事

阿里P7架构师对Java虚拟机、类加载机制是怎么理解的?

概述 类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:加载 (Loading).验证(Verification).准备(Preparation).解析(Resolution).初始化 (Initialization).使用(Using)和卸载(Unloading)7 个阶段.其中验证.准备.解析 3 个部分统称为连接(Linking) 于初始化阶段,虚拟机规范则是严格规定了有且只有 5 种情况必须立即对类进行“初始 化”(而加载.验证.准备自然需要在此之前开始): 1)遇到

阿里P7架构师是如何解决跨域问题的!你有遇到吗?

现在越来越多的项目就算是一个管理后端也偏向于使用前后端分离的部署方式去做,为了顺应时代的潮流,一前后端分离就产生了跨域问题,所以许多同学把跨域和前后端分离项目联系在了一起,其实跨域产生的原因并不是前后端分离导致的,那我们一起来看一下,希望可以靠这一篇文章解答大家所有的跨域问题 一.跨域产生的条件 使用xmlHttpRequest,即我们通常说的ajax请求 浏览器做了这个事 访问的域名不同,即访问的html页面是a域名下的,但内部js发送的ajax请求的目标地址却是b域名 以上三个条件缺一不可,

从普通Java程序员到阿里高级架构师,他用了6年!

6年间,一位架构师待过四大门户中的两户,已完成了工程师到架构师的蜕变.经手几款从零到一产品的开发和增涨,也亲身经历国內最大社交网络平台亿级数据流量和用户的架构设计及优化工作.在工作中思路清晰.尽职尽责,是同事们心目中出色 Problem Solver.参加工作时间:8 年服务公司:4 家(含四大门户中的两户)近期岗位:Java 架构师职场关键词:社交网络平台.高并发系统架构设计.技术团队管理.多款从零到一的产品城市! 问:介绍一下下你自身 答:我 2007 年本科大学毕业,前 2 年在一家传统式

阿里P8架构师谈:消息中间件介绍、典型使用场景、以及使用原则

阿里P8架构师谈:消息中间件介绍.典型使用场景.以及使用原则大型分布式架构里一定会涉及到消息中间件,今天先谈谈消息中间件. 本文作者 陈睿 优知学院创始人 曾任职阿里巴巴高级软件工程师.百度研发经理.携程定制旅游CTO 常用的消息队列有ActiveMQ,RabbitMQ,ZeroMQ,Kafka,MetaMQ,RocketMQ. 一.kafka1.不完全符合jms规范,注重吞吐量,类似udp 和 tcp 2.一般做大数据吞吐的管道 我们现在的用途就是负责在各个idc之间通信 3.量大对数据不是百

阿里P8架构师谈:2019的Java程序员要怎么提升?拿30K高薪?

最近去阿里的菜鸟国际做了一次面试交流,发现大公 阿里P8架构师谈:2019的Java程序员要怎么提升?拿30K高薪?司对于面试者的知识结构考核非常严谨,可以作为我们日常工作学习的指导.虽然很多人说面试问到的东西在实际工作中很少用到,甚至有「面试造火箭,工作拧螺丝」的说法.但从面试中,其实可以看得出来现在的公司对于面试者的知识体系要求.如果我们能在工作中就按着这样的要求去不断提升,那么在面试的时候必然也能游刃有余. 具有一到五年开发经验的程序员 需要学习的内容? 技术学到这个阶段,很容易遇到瓶颈,

CPU的快速互联通道(QPI)详解

翻译自:http://www.hardwaresecrets.com/article/Everything-You-Need-to-Know-About-The-QuickPath-Interconnect-QPI/610/1 自Intel有CPU开始,便一直采用的是称之为"前端总线(Front Side Bus, FSB)"的外部总线.前端总线是由内存和I/O共享的一条通往CPU的通道.新一代的Intel 处理器将内置内存控制器,所以该处理器将提供两个通道:连接CPU和内存的内存总线

《信息系统项目管理师软考辅导——3年真题详解与全真模拟》主要创新点、关注点

<信息系统项目管理师软考辅导--3年真题详解与全真模拟>主要创新点.关注点 新增2014年5月.11月两份真题试卷的360°透彻解析: 更新2013年5月.11月真题试卷的解析: 紧扣考纲,基于历年真题分析,心血创作了一套全新的全真模拟卷: 与时俱进创作了部分前沿信息技术(例如,4G技术.云数据中心.大数据技术等).法规标准的新题,并更新至各份闯关密卷中: 细致地订正了前一版书籍在编写.校对.排版.印刷等环节中所存在的错漏之处(例如,部分语句表述不够准确到位,部分数据上标排版错位等问题),对待