


版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、在实际工作中 Redis 最常用的两个使用场景是什么?一个是数据缓存,另一个就是 Session 共享。Spring Boot 这两个场景都做了一些优化,让我们在实际项目中使用非常的方便。数据缓存使用 Redis 做为数据缓存是最常用的场景了。我们知道绝大多数的 /系统,最先遇到的一个性能瓶颈就是数据库,使用 Redis 做数据库的前置缓存,可以非常有效的降低数据库的 ,从而提升整个系统的响应效率和并发量。Spring Boot 也提供了非常简单的解决方案,这里给大家演示最的三个注解: Cacheable 、 CacheEvict 、 CachePut 。spring-boot-starter
2、-cache在开始使用这三个注解之前,给大家介绍一个新的组件 spring-boot-starter-cache 。<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId></dependency>spring-boot-starter-cache 是 Spring Boot 提供缓存支持的 starter 包。 spring-boot-starter- cache 会
3、进 行 缓 存 的 自 动 化 配 置 和 识 别 , Spring Boot 为 Redis 自 动 配 置 了RedisCacheConfiguration 等信息。spring-boot-starter-cache 中的注解也主要是使用了 Spring Cache 提供的支持。CacheableCacheable 是用来 方法是可缓存的,将结果 到缓存中以便后续使用相同参数调用时不需执行实际的方法,直接从缓存中取值。 Cacheable 可以标记在一个方法上,也可以标记在一个类上。当标记在一个方法上时表示该方法是支持缓存的,当标记在一个类上 表示该类所有的方法都是支持缓存的。先来一个最简
4、单的例子体验一下:RequestMapping("/hello") Cacheable(value="helloCache") public String hello(String name) System.out.println("没有走缓存!");return "hello "+name;来测试一下,启动项目后 : 地址:方法,内容直接由缓存返回。输出: 没有走缓存! ,再次,输出栏没有变化,说明这次没有走 hello() 这个Cacheable(value="helloCache") 这个
5、注释的意思是, 当调用这个方法的时候, 会从一个名叫helloCache 的缓存中 ,如果没有,则执行实际的方法(也 数据库),并将执行的结果1/9存入缓存中,否则返回缓存中的对象。这里的缓存中的 key 就是参数 name,value 就是返回的String 值。Cacheable 支持如下几个参数:value:缓存的名称。key:缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合。condition:触发条件,只有满足条件的情况才会加入缓存,默认为空,既表示全部都加入缓 存,支持 SpEL。把上面的方法稍微改成这样:RequestM
6、apping("/condition") Cacheable(value="condition",condition="#name.length() <= 4") public String condition(String name) System.out.println("没有走缓存!");return "hello "+name;启动后浏览器执行:, 第一次输出栏输出: 没有走缓存! , 再次执行无输出表明, 已经走缓存。浏览器执行:?name=ityouknow ,浏览器执行多次仍
7、然一直输出: 没有走缓存! 说明条件 condition 生效。结合数据库的使用来做测试:RequestMapping("/getUsers") Cacheable(value="usersCache",key="#public List<User> getUsers(Stringname",condition="#name.length() >= 6")name)List<User> users=userRepository.findBy System.out.println(&qu
8、ot;执行了数据库操作");return users;name(name);启动后浏览器执行:。输出栏输出:Hibernate: select user0_.id as id1_0_, user0_.执行了数据库操作2_0_, user0_.name asnas多 次 执 行 , 仍 然 输 出 上 面 的 结 果 , 说 明 每 次 请 求 都 执 行 了 数 据 库 操 作 。 再 输 入 :进试。只有第一次返回了上面的内容,再次执行输出栏没有变化,说明后面的请求经从缓存中拿取了数据。最后总结一下:当执行到一个被 Cacheable 注解的方法时,Spring 首先检查 cond
9、ition 条件是否满足,如果不满足,执行方法,返回;如果满足,在缓存空间中查找使用 key的对象,如果找2/9到,将找到的结果返回,如果没有找到执行方法,将方法的返回值以 key-value 对象的方式存入缓存中,然后方法返回。需要注意的是当一个支持缓存的方法在对象内部被调用时是触发缓存功能的。CachePut项目运行中会对数据库的信息进行更新,如果仍然使用 Cacheable 就会导致数据库的信息和缓存的信息不一致。在以往的项目中,我们一般更新完数据库后,再手动删除掉 Redis 中对应的缓存, 以保证数据的一致性。Spring 提供了另外的一种解决方案,可以优雅的去更新缓存。与 Cach
10、eable 不同的是使用 CachePut 标注的方法在执行前,去检查缓存中是否存在之前执行过的结果,而是每次都会执行该方法,并将执行结果以键值对的形式存入指定的缓存中。以上面的方法为例,再来做一个测试:RequestMapping("/getPutUsers") CachePut(value="usersCache",key="#public List<User> getPutUsers(Stringname")name) List<User> users=userRepository.findBy Syst
11、em.out.println("执行了数据库操作");return users;name(name);新增一个 getPutUsers 方法,value、key 设置和 getUsers 方法保持一致,使用 CachePut。同时手动在数据库一条 nikename 为:ityouknow 的用户数据。:户信息,再并没有返回用户昵称为 ityouknow 的用可以查看到此用户的就可以看到用户昵称为地址:信息,再次地址:ityouknow 的信息了。说明执行在方法上CachePut 配置方法CachePut 会自动执行方法,并将结果存入缓存。value 缓存的名称。key 缓存
12、的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合。condition 缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存。可以看出 CachePut 的参数和使用方法基本和 Cacheable 一致。CachePut 也可以标注在类上和方法上。CacheEvict3/9CacheEvict 是用来标注在需要清除缓存元素的方法或类上的。当标记在一个类上时表示其中所有的方法的执行都会触发缓存的清除操作。CacheEvict 可以指定的属性有 value、key、condition、all
13、Entries 和 beforeInvocation。其中 value、key 和 condition 的语义与 Cacheable 对应的属性类似。即 value 表示清除操作是发生在哪些 Cache 上的(对应 Cache 的名称);key 表示需要清除的是哪个 key,如未指定则会使用默认策略生成的 key;condition 表示清除操作发生的条件。下面来介绍一下新出现的两个属性 allEntries 和 beforeInvocation。allEntries 属性allEntries 是 boolean 类型,表示是否需要清除缓存中的所有元素。默认为 false,表示不需要。当指定了
14、 allEntries 为 true 时,Spring Cache 将忽略指定的 key。有的时候我们需要 Cache 一下清除所有的元素,这比一个一个清除元素更有效率。在上一个方法中我们使用注解: CachePut(value="usersCache",key="#name") 来更新缓存,但如果不写 key="#name" , Spring Boot 会以默认的 key 值去更新缓存, 导致最上面的方法getUsers() 方法并没有获取最新的数据。但是现在使用 CacheEvict 就可以解决这个问题了,它会将所有以 users
15、Cache 为名的缓存全部清除。来看个例子:RequestMapping("/allEntries")CacheEvict(value="usersCache", allEntries=true)public List<User> allEntries(Stringname) List<User> users=userRepository.findBy System.out.println("执行了数据库操作");return users;name(name);手 动 修 改 用 户 表 的 相 关 信 息 ,
16、 如时 间 。:?后,再name=ityouknow 发现缓存中的数据并没有更新。再次地址会发现数据已经更新,并且输出栏输出 执行了数据库操作 ,这表明已经将名为 usersCache 的缓存清空。beforeInvocation 属性清除操作默认是在对应方法执行之后触发的,即方法如果因为抛出异常而未能返回不会触发清除操作。使用 beforeInvocation 可以改变触发清除操作的时间,当我们指定该属性值为true 时,Spring 会在调用该方法之前清除缓存中的指定元素。RequestMapping("/beforeInvocation")CacheEvict(val
17、ue="usersCache", allEntries=true, beforeInvocation=true)public void beforeInvocation() throw new RuntimeException("test beforeInvocation");来做一个测试,在方法中添加一个异常,usersCache 的缓存是否被更新。地址:查看4/9按照上面的实验步骤: 手动修改用户表的相关信息,name=ityouknow发现缓存中的数据:并没?访有更新。再问会 报 错 误 , 先 不 用 管 这 里 , 再 次地址会发现数据已经更新
18、,并且输出栏输出 执行了数据库操作 。这表明虽然在测试的过程中方法抛出了异常,但缓存中名为 usersCache 的被清空。Cacheable 、 CacheEvict 、 CachePut 三个注解非常灵活,满足了我们对数据缓存的绝大多数使用场景,并且使用起来非常的简单而又强大,在实际工作中我们可以灵活 搭配使用。Session 共享Session什么是 Session由于 HTTP 协议是无状态的协议,所以服务端需要用户的状态时,就需要用某种机制来识具体的用户。Session 是另一种客户状态的机制,不同的是 Cookie 保存在客户端浏览器中,而Session 保存在服务器上。客户端浏览
19、器服务器的时候,服务器把客户端信息以某种形式在服务器上。这就是 Session。客户端浏览器再次时只需要从该 Session 中查找该客户的状态就可以了。为什么需要 Session 共享在互联网行业中用户量巨大,往往需要多个节点共同对外提供某一种服务,如下图:用户的请求首先会到达前置网关,前置网关根据路由策略将请求分发到后端的服务器,这就会出现第一次的请求会交给服务器 A 处理,下次的请求可能会是服务B处理,如果不做 Session 共享的话,就有可能出现用户在服务 A 登录了,下次请求的时候到达服务 B 又要求用户重新登录。前置网关一般使用 lvs、Nginx 或者 F5 等软硬件,有些软件
20、可以指定策略让用户每次请求都分发到同一台服务器中,这也有个弊端,如果当其中一台服务 Down 掉之后,就会出现一批用户失5/9效。在实际工作中建议使用外部的缓存设备来共享 Session,避免单个节点挂掉而影响服务,使用外部缓存 Session 后,我们的共享数据都会放到外部缓存容器中,服务本身就会变成无状态的服务,可以随意的根据流量的大小增加或者减少负载的设备。一般 Tomcat 有自带的 Session 共享功能,但是使用起来并不是很便利, 用,最常见的方式就是使用 Redis 来实现后端服务的 Session 共享。也不推荐大规模的使Spring SessionSpring Sessio
21、n 提供了一套创建和管理 Servlet HttpSession 的方案。Spring Session 提供了集群Session(Clustered Sessions)功能,默认采用外置的 Redis 来Session 共享的问题。Session 数据,以此来解决Spring Session 为企业级 Java 应用的 session 管理带来了革新,使得以下的功能更加容易实现:API 和用于管理用户会话的实现。以应用程序容器(即 Tomcat)中性的方式替换 HttpSession。HttpSession -将 session 所保存的状态卸载到特定的外部 session中,如 Redis
22、或 Apache Geode 中,它们能够以于应用服务器的方式提供高质量的集群。支持每个浏览器上使用多个 session,从而能够很容易地构建更加丰富的终端用户体验。session id 如何在客户端和服务器之间进行交换,这样的话就能很容易地编写 RestfulAPI,因为它可以从 HTTP 头信息中获取 session id,而不必再依赖于 cookie。当用户使用 WebSocket请求的时候,能够保持 HttpSession 处于活跃状态。需要说明的很重要的一点就是,Spring Session 的项目并不依赖于 Spring 框架,所以,我们甚至能够将其应用于不使用 Spring 框架
23、的项目中。Spring 为 Spring Session 和 Redis 的集成提供了组件:spring-session-data-redis,下面演示如何使用。快速集成引入依赖包<dependency><groupId>org.springframework.session</groupId><artifactId>spring-session-data-redis</artifactId></dependency>Session 配置Configuration EnableRedisHttpSession(maxIna
24、ctiveIntervalInSeconds = 86400*30) public class SessionConfig 6/9maxInactiveIntervalInSeconds: 设置 Session 失效时间,使用 Redis Session 之后, 原 Boot 的 server.session.timeout 属性不再生效。仅仅需要这两步 Spring Boot 分布式 Session 就配置完成了。测试验证在 Web 层写两个方法进行验证。RequestMapping(value = "/setSession", method = RequestMetho
25、d.GET) public Map<String, Object> setSession (HttpServletRequest request)Map<String, Object> map = new HashMap<>(); request.getSession().setAttribute("request Url", request.getRequestURL(); map.put("request Url", request.getRequestURL();return map;上面这个方法就是获取页面的请
26、求地址,并把请求地址放入到 Session 中,并将结果返回。RequestMapping(value = "/setSession")public Map<String, Object> setSession (HttpServletRequest request) Map<String, Object> map = new HashMap<>(); request.getSession().setAttribute("message", request.getRequestURL(); map.put("
27、request Url", request.getRequestURL();return map;第一个方法获取页面的请求地址,并把请求地址放入 Key 为 message 的 Session 中,并将结果返回。RequestMapping(value = "/getSession")public Object getSession (HttpServletRequest request) Map<String, Object> map = new HashMap<>(); map.put("sessionId", re
28、quest.getSession().getId();map.put("message", request.getSession().getAttribute("message");return map;第二个方式获取 Session 中的请求中的 Session Id 和 Key 为 message 的信息封装返回。在测试前需要将项目 spring-boot-redis-session一份,改名为 spring-boot-redis-session-1 并将端口改为:9090(server.port=9090)。修改完成后依次启动两个项目。首先Url&
29、quot;:"8080 端口的服务, 浏览器输入" ;浏览器栏输入:, 返回: "request,返回信息如下:7/9"sessionId":"432765e1-049e-4e76-980c-d7f55a232d42","message":"说明 url 地址信息已经存入到 Session 中。9090 端口的服务,浏览器栏输入:,返回信息如下:"sessionId":"432765e1-049e-4e76-980c-d7f55a232d42","
30、;message":"通过对比发现,8080 和 9090 服务返回的 Session 信息完全一致,说明已经实现了 Session 共享。模拟登录在实际中作中常常使用共享 Session 的方式去保存用户的登录状态,避免用户在不同的页面来回登录。来简单模拟一下这个场景,假设有一个 index 页面,必须是登录的用户才可以,如果用户没有登录给出提示。首先在一台实例上登录后,再次另外一台的 index 看它是否需要登录,来验证统一登录是否。添加登录方法,登录后将用户信息存放到 Session 中。RequestMapping(value = "/login")public String login (HttpServletRequest request,String userName,String password) String msg="logon failure!"User user= userRepository.findByUserName(userName);if (user!=null && user.getP
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 育苗知识与技能培训考核试卷
- 科研伦理审查与违规处理考核试卷
- 染整行业绿色制造与清洁生产考核试卷
- 染料在农业生物防治中的应用考核试卷
- 竞赛场地布局与设计考核试卷
- 批发商财务管理与风险控制考试考核试卷
- 租赁农机在农业机械化推广中的作用考核试卷
- 拼多多农产品电商平台活动策划代运营服务协议
- 海关关员岗位海关业务流程优化聘用合同
- 城市管理系统数据收集与合规利用协议
- 水下探测技术发展-洞察分析
- DB21T 3508-2021 旅游景区木栈道设置与维护规范
- 扁桃体癌护理查房
- 医疗技术销售技巧
- 2024专利代理人考试真题及答案
- 2025年高考数学模拟卷(一)含答案及解析
- 高英-Mark-Twain-Mirror-of-America原文+翻译+修辞
- 中国老年骨质疏松症诊疗指南(2023)解读课件
- 高中英语新课程标准解读课件
- 《宠物营养与食品》课件-1.3宠物的蛋白质营养
- 2024年湖南省中考道德与法治试题卷(含答案解析)
评论
0/150
提交评论