02_Springboot集成Redis【单机/集群】

@author Jacky wang
转载请注明出处 , https://www.jianshu.com/p/4cfedabca746

2018年09月12日,第一次补充更新.

看了网上一些Springboot集成Redis的很多资料,发现对Redis的配置复杂了,自己总结了Springboot集成Redis的简单方式。

一. SpringBoot集成Redis单机版

1.1. 创建Maven工程

搭建SpringBoot工程,包结构如下:

SpringBoot的标准包结构···
3.png

1.2. pom文件添加依赖,properties添加配置

pom.xml :
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.dream</groupId>
    <artifactId>spring-redis</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.8.RELEASE</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <!-- Springboot集成Redis -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <!-- Springboot测试 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- 热部署插件 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <fork>true</fork>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

-----------------------------------------------------------------------------------------------------

application.properties:(很多其实是默认的,这里全部列出来)
    #指定连接工厂使用的Database index,默认为: 0
    spring.redis.database=0
    #指定Redis server host,默认为: localhost
    spring.redis.host=127.0.0.1
    #指定Redis server的密码
    #spring.redis.password=
    #指定连接池最大的活跃连接数,-1表示无限,默认为8
    spring.redis.pool.max-active=8
    #指定连接池最大的空闲连接数,-1表示无限,默认为8
    spring.redis.pool.max-idle=8
    #指定当连接池耗尽时,新获取连接需要等待的最大时间,以毫秒单位,-1表示无限等待
    spring.redis.pool.max-wait=-1
    #指定连接池中空闲连接的最小数量,默认为0
    spring.redis.pool.min-idle=2
    #指定redis服务端端口,默认: 6379
    spring.redis.port=6379
    #指定redis server的名称
    #spring.redis.sentinel.master
    #指定sentinel节点,逗号分隔,格式为host:port.
    #spring.redis.sentinel.nodes
    #指定连接超时时间,毫秒单位,默认为0
    spring.redis.timeout=0

1.3. RedisTemplate的处理

/**
 * Redis数据库操作对象
 * @author wwj
 */
@Component
public class RedisClient {

    @Autowired
    private RedisTemplate redisTemplate;
    
    /**
     * 写入缓存
     * @param key
     * @param value
     * @return
     */
    
    public boolean set(final String key, Object value) {
        boolean result = false;
        try {
            ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
            operations.set(key, value);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
    
    /**
     * 写入缓存设置时效时间
     * @param key
     * @param value
     * @return
     */
    public boolean set(final String key, Object value, Long expireTime) {
        boolean result = false;
        try {
            ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
            operations.set(key, value);
            redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
    
    /**
     * 读取缓存
     * @param key
     * @return
     */
    public Object get(final String key) {
        Object result = null;
        ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
        result = operations.get(key);
        return result;
    }
    
    /**
     * 判断缓存中是否有对应的value
     * @param key
     * @return
     */
    public boolean exists(final String key) {
        return redisTemplate.hasKey(key);
    }
    
    /**
     * 删除对应的value
     * @param key
     */
    public void remove(final String key) {
        if (exists(key)) {
            redisTemplate.delete(key);
        }
    }
    
    /**
     * 批量删除对应的value
     * @param keys
     */
    public void remove(final String... keys) {
        for (String key : keys) {
            remove(key);
        }
    }

    /**
     * 批量删除key
     * @param pattern
     */
    public void removePattern(final String pattern) {
        Set<Serializable> keys = redisTemplate.keys(pattern);
        if (keys.size() > 0)
            redisTemplate.delete(keys);
    }

    /**
     * 哈希 添加
     * @param key
     * @param hashKey
     * @param value
     */
    public void hmSet(String key, Object hashKey, Object value){
        HashOperations<String, Object, Object>  hash = redisTemplate.opsForHash();
        hash.put(key,hashKey,value);
    }

    /**
     * 哈希获取数据
     * @param key
     * @param hashKey
     * @return
     */
    public Object hmGet(String key, Object hashKey){
        HashOperations<String, Object, Object>  hash = redisTemplate.opsForHash();
        return hash.get(key,hashKey);
    }

    /**
     * 列表添加
     * @param k
     * @param v
     */
    public void lPush(String k,Object v){
        ListOperations<String, Object> list = redisTemplate.opsForList();
        list.rightPush(k,v);
    }

    /**
     * 列表获取
     * @param k
     * @param l
     * @param l1
     * @return
     */
    public List<Object> lRange(String k, long l, long l1){
        ListOperations<String, Object> list = redisTemplate.opsForList();
        return list.range(k,l,l1);
    }

    /**
     * 集合添加
     * @param key
     * @param value
     */
    public void add(String key,Object value){
        SetOperations<String, Object> set = redisTemplate.opsForSet();
        set.add(key,value);
    }

    /**
     * 集合获取
     * @param key
     * @return
     */
    public Set<Object> setMembers(String key){
        SetOperations<String, Object> set = redisTemplate.opsForSet();
        return set.members(key);
    }

    /**
     * 有序集合添加
     * @param key
     * @param value
     * @param scoure
     */
    public void zAdd(String key,Object value,double scoure){
        ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
        zset.add(key,value,scoure);
    }

    /**
     * 有序集合获取
     * @param key
     * @param scoure
     * @param scoure1
     * @return
     */
    public Set<Object> rangeByScore(String key,double scoure,double scoure1){
        ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
        return zset.rangeByScore(key, scoure, scoure1);
    }
}

到这里就可以使用,RedisClientRedis进行操作了,上面给出的方法比较全,可以选择需要用到的进行使用。

1.4. 测试

1.4.1 Application入口类
@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}
1.4.2 User实体类
为了测试,还提供了一个User实体类,因为产生了传输过程,因此这里必须要实现Serializable接口。
public class User implements Serializable {
        private static final long serialVersionUID = 1L;
        private String username;
        private int age;
        
        public User() {
            super();
        }
    
        public User(String username, int age) {
            super();
            this.username = username;
            this.age = age;
        }
    
        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;
        }
    
        @Override
        public String toString() {
            return "User [username=" + username + ", age=" + age + "]";
        }
    }
1.4.3 SpringbootRedisTest测试类
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)//指定springboot的启动类
public class SpringBootRedisTest {

    @Autowired
    private RedisClient redisClient;
    
    @Test
    public void testSet() {
        String key = "keyTest";
        String val = "keyVal2";
        redisClient.set(key, val);
        User user = new User("jack", 24);
        redisClient.set("user", user);
    }
    
    @Test
    public void testGet() {
        String key = "keyTest";
        String key2 = "user";
        String val = (String)redisClient.get(key);
        User user = (User)redisClient.get(key2);
        System.err.println(val);
        System.err.println(user);
    }

    @Test
    public void testRemove() {
        String key = "keyTest";
        String key2 = "user";
        redisClient.remove(key);
        redisClient.remove(key2);
    }
    
    @Test
    public void testSetExpire() throws Exception {
        String key = "testExpire";
        String value = "hello";
        long expireTime = 60L;//60秒后消失
        redisClient.set(key, value, expireTime);
    }
}

以上就是Springboot集成Redis的全部过程,实现起来是非常简单的。到这里总结一下:

1. 添加pom.xml : spring-boot-starter-data-redis的依赖
2. 配置application.properties
3. 对RedisTemplate进行部分功能的封装。

具体的测试结果就不贴出来了,这里贴一下testSetExpire()的结果。

1.png

二. SpringBoot集成Redis集群版

2.1. SpringBoot集成Redis集群的两种方式:

2.1.1. SpringBoot内置配置支持:

步骤:

  • 引入RedisMaven依赖
  • 配置application.properties支持Redis集群
  • 引入RedisTemplate使用
  • 测试
1. Maven依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        
2. 配置application.properties支持Redis集群
    # RedisProperties
    # 在群集中执行命令时要遵循的最大重定向数目。
    spring.redis.cluster.max-redirects=3
    # (普通集群,不使用则不用开启)以逗号分隔的“主机:端口”对列表进行引导。
    spring.redis.cluster.nodes=192.168.5.122:9001,192.168.5.122:9002
    spring.redis.cluster.timeout=1000\
    
3. 引入RedisTemplate使用
    见单机版的RedisClient
    
4. 测试

@SpringBootTest(classes = Application.class)
@RunWith(value = SpringRunner.class)
public class TestRedis {

    @Autowired
    private RedisClient redisClient;
    
    @Test
    public void setTest() throws Exception {
        List<User> users = new ArrayList<User>();
        User user = new User("coco", "coco", "on");     
        User user2 = new User("jack", "jack", "on");
        user.setCreateDate(new Date());
        user2.setCreateDate(new Date());
        users.add(user);
        users.add(user2);
        redisClient.set("users", FastJsonUtils.toJSONStringWithDateFormat(users));
    }
    
    @Test
    public void getTest() throws Exception {
        String json = (String) redisClient.get("users");
        List<User> users = FastJsonUtils.toList(json, User.class);
        for (User record : users) {
            System.err.println(record.getUsername());
        }
    }
}

操作成功。
2.1.2 . 自定义JedisClusterConfig配置类支持Redis集群

步骤:

  • 引入RedisMaven依赖

  • 自定义Redis的集群配置并以实体类接收

  • 编写JedisClusterConfig的配置类

  • 使用JedisCluster操作Redis

1. 引入Redis的Maven依赖(省略)
2. 自定义Redis的集群配置并以实体类接收

config/redis.properties:

# 本地环境集群
jack.redis.pool.nodes=192.168.5.122:9001,192.168.5.122:9002,192.168.5.122:9003
#redis超时时间,单位:秒
jack.redis.pool.timeout=7200
jack.redis.pool.maxAttempts=5
    
@Component
@ConfigurationProperties(prefix = "jack.redis.pool")
@PropertySource("classpath:/config/redis.properties")
public class RedisProperty {

    private String nodes;// redis集群节点
    private int timeout;// 连接超时时间
    private int maxAttempts;// 重连次数
 
    省略getter();setter();
}

3.  编写 JedisClusterConfig 的配置类
    
@SpringBootConfiguration
public class JedisClusterConfig {

    @Autowired
    private RedisProperty redisProperty;
    
    @Bean
    public JedisCluster getJedisCluster() {
        String[] redisArray = redisProperty.getNodes().split(",");//获取服务器数组,不考虑空指针问题
        Set<HostAndPort> nodes = new HashSet<>();
        for (String ipport : redisArray) {
            String[] ipports = ipport.split(":");
            nodes.add(new HostAndPort(ipports[0].trim(), Integer.valueOf(ipports[1].trim())));
        }
        return new JedisCluster(nodes, redisProperty.getTimeout(), redisProperty.getMaxAttempts());
    }
}

4. 使用配置类中的JedisCluster操作Redis

/**
 * @ClassName: JedisClusterClient
 * @Description:TODO(redis集群的基础操作工具)
 * @author: wwj
 * @date: 2018年8月27日 下午3:15:22
 */
@Component
public class JedisClusterClient {

    @Autowired
    private JedisCluster jedisCluster;
    @Autowired
    private RedisProperty redisProperty;

    /**
     * 写入缓存
     * 
     * @param key
     * @param value
     * @return
     */

    public boolean set(final String key, Object value) {
        boolean result = false;
        try {
            if (value instanceof String) {
                jedisCluster.set(key, value.toString());
            } else {
                jedisCluster.set(key, FastJsonUtils.toJSONStringWithDateFormat(value));
            }
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 写入缓存设置时效时间
     * 
     * @param key
     * @param value
     * @return
     */
    public boolean set(final String key, Object value, Long expireTime) {
        boolean result = false;
        try {
            if (value instanceof String) {
                jedisCluster.setex(key, Integer.valueOf(expireTime + ""), value.toString());
            } else {
                jedisCluster.setex(key, Integer.valueOf(expireTime + ""), FastJsonUtils.toJSONStringWithDateFormat(value));
            }
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 设置缓存,并且由配置文件指定过期时间
     * 
     * @param key
     * @param value
     */
    public void setWithExpireTime(String key, String value) {
        try {
            int expireSeconds = redisProperty.getTimeout();
            set(key, value, Long.valueOf(expireSeconds));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 读取缓存
     * 
     * @param key
     * @return
     */
    public String get(final String key) {
        return jedisCluster.get(key);
    }

    /**
     * 判断缓存中是否有对应的value
     * 
     * @param key
     * @return
     */
    public boolean exists(final String key) {
        return jedisCluster.exists(key);
    }

    /**
     * 删除对应的value
     * 
     * @param key
     */
    public void remove(final String key) {
        if (exists(key)) {
            jedisCluster.del(key);
        }
    }

    /**
     * 批量删除对应的value
     * 
     * @param keys
     */
    public void remove(final String... keys) {
        for (String key : keys) {
            remove(key);
        }
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,490评论 18 139
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,678评论 6 342
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,044评论 25 707
  • 闲坐品茶与读书, 静心修养万事阔。 诗书下酒味无穷, 良辰美景尽其中。 (注,无押韵,自由体随意诗。)
    凡高潇湘花子阅读 63评论 0 1
  • 上帝在创造牛的时候,对牛说道:“你只能活60年。但要一生为人类干活。” 于是牛放弃了30年的生命,只愿活到30岁。...
    刘鼻涕26阅读 210评论 0 0