设为首页 收藏本站
查看: 1739|回复: 0

[经验分享] redis 学习笔记(5)-Spring与Jedis的集成

[复制链接]

尚未签到

发表于 2015-7-20 08:06:28 | 显示全部楼层 |阅读模式
  首先不得不服Spring这个宇宙无敌的开源框架,几乎整合了所有流行的其它框架,http://projects.spring.io/spring-data/ 从这上面看,当下流行的redis、solr、hadoop、mongoDB、couchBase... 全都收入囊中。对于redis整合而言,主要用到的是spring-data-redis
  
  使用步骤:
  一、pom添加依赖项



        
org.springframework.data
spring-data-redis
1.4.1.RELEASE

  其它Spring必备组件,比如Core,Beans之类,大家自行添加吧
  观察一下:
DSC0000.jpg
  jedis、jredis等常用java的redis client已经支持了,不知道以后会不会集成Redisson,spring-data-redis提供了一个非常有用的类:StringRedisTemplate
DSC0001.jpg
  对于大多数缓存应用场景而言,字符串是最常用的缓存项,用StringRedisTemplate可以轻松应付。
  
  二、spring配置


DSC0002.gif DSC0003.gif


1     
3         
4            
5                 
6            
7         
8         
9            
10                 
11                     
12                                         
13                 
14                 
15                     
16                                    
17                 
18                                    
19                     
20                                    
21                 
22            
23         
24     
25
26      
28                 
29     
30
31     
32         
33     
View Code  这里我们使用Sentinel模式来配置redis连接,从上篇学习知道,sentinel是一种高可用架构,个人推荐在生产环境中使用sentinel模式。
  注:26-28行,经试验,如果修改了默认端口,这里必须明细指定hostName及port,否则运行后,无法正确读写缓存,参考下面的配置:



   





  其中hostName为当前master的IP,port为redis-server的运行端口(非sentinel端口),此外还要设置usePool为false,由于sentinel可能会自行切换master节点,如果不清楚当前的master节点是哪台机器,可以用前面提到的命令./redis-cli -p  sentinel masters查看,或者用java代码输出,参考下面的代码:



1         ApplicationContext ctx = new FileSystemXmlApplicationContext("/opt/app/spring-redis.xml");
2         StringRedisTemplate template = ctx.getBean(StringRedisTemplate.class);
3         for (RedisServer m : template.getConnectionFactory().getSentinelConnection().masters()) {
4             logger.debug(m);
5         }
  另外 这里的value值建议设置成false,如果改成true,经实际测试,发现在有些环境下会报如下错误:
  redis.clients.jedis.exceptions.JedisDataException: ERR unknown command 'SET'
  其它注意事项:
  配置文件中的sentinels属性的Set 中的节点,并非一定要在同一个master下,也可以是归属于多个master,即:如果这里配置了10个node信息,其中1-3归属于master1,剩下的4-10属于master2,这也是允许的。
  这样调用时,通过StringRedisTemplate.getConnectionFactory().getSentinelConnection().masters()可以返回一个master的列表,然后代码中根据需要,向某一个需要的master写入缓存.
  
  三、单元测试





1     @Test
2     public void testSpringRedis() {
3         ConfigurableApplicationContext ctx = null;
4         try {
5             ctx = new ClassPathXmlApplicationContext("spring.xml");
6
7             StringRedisTemplate stringRedisTemplate = ctx.getBean("stringRedisTemplate", StringRedisTemplate.class);
8
9             // String读写
10             stringRedisTemplate.delete("myStr");
11             stringRedisTemplate.opsForValue().set("myStr", "http://yjmyzz.iyunv.com/");
12             System.out.println(stringRedisTemplate.opsForValue().get("myStr"));
13             System.out.println("---------------");
14
15             // List读写
16             stringRedisTemplate.delete("myList");
17             stringRedisTemplate.opsForList().rightPush("myList", "A");
18             stringRedisTemplate.opsForList().rightPush("myList", "B");
19             stringRedisTemplate.opsForList().leftPush("myList", "0");
20             List listCache = stringRedisTemplate.opsForList().range(
21                     "myList", 0, -1);
22             for (String s : listCache) {
23                 System.out.println(s);
24             }
25             System.out.println("---------------");
26
27             // Set读写
28             stringRedisTemplate.delete("mySet");
29             stringRedisTemplate.opsForSet().add("mySet", "A");
30             stringRedisTemplate.opsForSet().add("mySet", "B");
31             stringRedisTemplate.opsForSet().add("mySet", "C");
32             Set setCache = stringRedisTemplate.opsForSet().members(
33                     "mySet");
34             for (String s : setCache) {
35                 System.out.println(s);
36             }
37             System.out.println("---------------");
38
39             // Hash读写
40             stringRedisTemplate.delete("myHash");
41             stringRedisTemplate.opsForHash().put("myHash", "PEK", "北京");
42             stringRedisTemplate.opsForHash().put("myHash", "SHA", "上海虹桥");
43             stringRedisTemplate.opsForHash().put("myHash", "PVG", "浦东");
44             Map hashCache = stringRedisTemplate.opsForHash()
45                     .entries("myHash");
46             for (Map.Entry entry : hashCache.entrySet()) {
47                 System.out.println(entry.getKey() + " - " + entry.getValue());
48             }
49
50             System.out.println("---------------");
51
52         } finally {
53             if (ctx != null && ctx.isActive()) {
54                 ctx.close();
55             }
56         }
57
58     }
View Code  运行一下,行云流水般的输出:
  ...
  信息: Created JedisPool to master at 10.6.144.***:7030
http://yjmyzz.iyunv.com/
---------------
0
A
B
---------------
C
B
A
---------------
SHA - 上海虹桥
PVG - 浦东
PEK - 北京
---------------
  ...
  注意红色标出部分,从eclipse控制台的输出,还能看出当前的master是哪台服务器
  这里再补充一点小技巧:如果想遍历所有master及slave可以参考以下代码





1     @Test
2     public void testGetAllMasterAndSlaves() {
3         ApplicationContext ctx = new FileSystemXmlApplicationContext("D:/spring-redis.xml");
4         StringRedisTemplate template = ctx.getBean(StringRedisTemplate.class);
5         RedisSentinelConnection conn = template.getConnectionFactory().getSentinelConnection();
6         for (RedisServer m : conn.masters()) {
7             System.out.println("master => " + m);//打印master信息
8             Collection slaves = conn.slaves(m);
9             //打印该master下的所有slave信息
10             for (RedisServer s : slaves) {
11                 System.out.println("slaves of " + m + " => " + s);
12             }
13             System.out.println("--------------");
14         }
15         ((FileSystemXmlApplicationContext) ctx).close();
16     }
View Code  输出类似下面的结果:
  master => 172.20.16.191:6379
slaves of 172.20.16.191:6379 => 172.20.16.192:6379
  注:这里输出的slaves列表,经实际测试,发现只是根据redis server端的配置呆板的返回slave node列表,不管这些node是死是活,换句话说,就算某个slave已经down掉,这里依然会返回。
  
  三、POJO对象的缓存
  Spring提供的StringRedisTemplate只能对String操作,大多数情况下已经够用,但如果真需要向redis中存放POJO对象也不难,我们可以参考StringRedisTemplate的源码,扩展出ObjectRedisTemplate





1 package org.springframework.data.redis.core;
2
3 import org.springframework.data.redis.connection.DefaultStringRedisConnection;
4 import org.springframework.data.redis.connection.RedisConnection;
5 import org.springframework.data.redis.connection.RedisConnectionFactory;
6 import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
7 import org.springframework.data.redis.serializer.RedisSerializer;
8
9 public class ObjectRedisTemplate extends RedisTemplate {
10
11     public ObjectRedisTemplate(RedisConnectionFactory connectionFactory,
12             Class clazz) {
13
14         RedisSerializer objectSerializer = new Jackson2JsonRedisSerializer(
15                 clazz);
16
17         RedisSerializer objectKeySerializer = new Jackson2JsonRedisSerializer(
18                 String.class);
19
20         setKeySerializer(objectKeySerializer);
21         setValueSerializer(objectSerializer);
22         setHashKeySerializer(objectSerializer);
23         setHashValueSerializer(objectSerializer);
24
25         setConnectionFactory(connectionFactory);
26         afterPropertiesSet();
27     }
28
29     protected RedisConnection preProcessConnection(RedisConnection connection,
30             boolean existingConnection) {
31         return new DefaultStringRedisConnection(connection);
32     }
33 }
View Code  然后就可以这样用了:





1     @Test
2     public void testSpringRedis() {
3         ConfigurableApplicationContext ctx = null;
4         try {
5             ctx = new ClassPathXmlApplicationContext("spring.xml");
6
7             JedisConnectionFactory connFactory = ctx.getBean(
8                     "jedisConnFactory", JedisConnectionFactory.class);
9
10             ObjectRedisTemplate template = new ObjectRedisTemplate(
11                     connFactory, SampleBean.class);
12
13             template.delete("myBean");
14             SampleBean bean = new SampleBean("菩提树下的杨过");
15             template.opsForValue().set("myBean", bean);
16
17             System.out.println(template.opsForValue().get("myBean"));
18            
19         } finally {
20             if (ctx != null && ctx.isActive()) {
21                 ctx.close();
22             }
23         }
24     }
View Code  其中SampleBean的定义如下:





1 package com.cnblogs.yjmyzz;
2
3 import java.io.Serializable;
4
5 public class SampleBean implements Serializable {
6
7     private static final long serialVersionUID = -303232410998377570L;
8
9     private String name;
10
11     public SampleBean() {
12     }
13
14     public SampleBean(String name) {
15         this.name = name;
16     }
17
18     public String getName() {
19         return name;
20     }
21
22     public void setName(String name) {
23         this.name = name;
24     }
25
26     public String toString() {
27         return "name:" + name;
28     }
29
30 }
View Code  注:由于不是标准的String类型,所以在redis控制台,用./redis-cli get myBean是看不到缓存内容的,只能得到nil的输出,不要误以为set没成功!通过代码是可以正常get到缓存值的。
  另外关于POJO对象的缓存,还有二个注意事项:
  a) POJO类必须要有默认的无参构造函数,否则反序列化时会报错
  b) ObjectRedisTemplate中的T不能是接口,比如 DomainModelA继承自接口 IModelA,使用ObjectRedisTemplate时,要写成ObjectRedisTemplate而不是ObjectRedisTemplate,否则反序列化时也会出错

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-88381-1-1.html 上篇帖子: Redis学习手册(虚拟内存) 下篇帖子: rtags——node.js+redis实现的标签管理模块
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表