Spring整合Jedis

1.单实例(想节约时间的请直接拖到下面跳过1、2部分)

step1:毫无疑问,首先需要在pom.xml中配置Jedis依赖

        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.9.0</version>
        </dependency>

step2:在resources中添加settings.properties,配置redis相关属性


#jedisPoolConfig
redis.minIdle=100
redis.maxIdle=500
redis.maxTotal=50000 
redis.maxWaitMillis=10000  
redis.testOnBorrow=true


#jedisPool
redis.host=127.0.0.1
redis.port=6379
redis.timeout=2000

step3:在spring-context.xml配置JedisPoolConfig及JedisPool

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="service,dao"/>

    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>classpath:settings.properties</value>
            </list>
        </property>
    </bean>

    <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <property name="maxIdle" value="${redis.maxIdle}" />
        <property name="maxTotal" value="${redis.maxTotal}" />
        <property name="maxWaitMillis" value="${redis.maxWaitMillis}" />
        <property name="testOnBorrow" value="${redis.testOnBorrow}" />
    </bean>

    <bean id="jedisPool" class="redis.clients.jedis.JedisPool">
        <constructor-arg name="poolConfig" ref="jedisPoolConfig" />
        <constructor-arg name="host" value="${redis.host}" />
        <constructor-arg name="port" value="${redis.port}" type="int" />
    </bean>

</beans>

JedisPool只有简单配置,如果需要增加其它配置项(如密码等),请自行参照JedisPool的构造方法进行配置

JedisPool.png

step4:在TestController中测试是否连接成功

package controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

@Controller
public class TestController {

    @Autowired
    private JedisPool jedisPool;

    @RequestMapping(value = "test",method = RequestMethod.GET,produces = "application/json;charset=utf-8")
    @ResponseBody
    public String test(){
        return jedisPool.getResource().ping();
    }

    public static void main(String[] args) {
        Jedis jedis = new Jedis("127.0.0.1",6379);
        System.out.println(jedis.ping());
    }

}

step5:启动、运行、报错

nested exception is java.lang.NoClassDefFoundError: org/apache/commons/pool2/impl/GenericObjectPoolConfig

查看源码发现JedisPoolConfig继承自GenericObjectPoolConfig

package redis.clients.jedis;

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;

public class JedisPoolConfig extends GenericObjectPoolConfig {
    public JedisPoolConfig() {
        this.setTestWhileIdle(true);
        this.setMinEvictableIdleTimeMillis(60000L);
        this.setTimeBetweenEvictionRunsMillis(30000L);
        this.setNumTestsPerEvictionRun(-1);
    }
}

而GenericObjectPoolConfig在package org.apache.commons.pool2.impl中,所以需要引入commons-pool2依赖

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
            <version>2.4.2</version>
        </dependency>

再次运行,得到“Pong”的response结果,测试成功
Ping.png

2.配置Redis简单主从复制

Jedis对redis的集群支持也很完善,实例化SharedJedisPool即可

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="service,dao,redis"/>


    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>classpath:settings.properties</value>
            </list>
        </property>
    </bean>

    <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <property name="maxTotal" value="${redis.maxTotal}" />
        <property name="maxIdle" value="${redis.maxIdle}" />
        <property name="minIdle" value="${redis.minIdle}" />
        <property name="maxWaitMillis" value="${redis.maxWaitMillis}" />
        <property name="testOnBorrow" value="${redis.testOnBorrow}" />
    </bean>

<!--
    <bean id="jedisPool" class="redis.clients.jedis.JedisPool" scope="singleton">
        <constructor-arg name="poolConfig" ref="jedisPoolConfig" />
        <constructor-arg name="host" value="${redis.host}" />
        <constructor-arg name="port" value="${redis.port}" type="int" />
    </bean>
-->

    <bean id="shardedJedisPool" class="redis.clients.jedis.ShardedJedisPool">
        <constructor-arg index="0" ref="jedisPoolConfig" />
        <constructor-arg index="1">
            <list>
                <bean class="redis.clients.jedis.JedisShardInfo">
                    <constructor-arg name="host" value="${redis.host1}" />
                    <constructor-arg name="port" value="${redis.port1}" />
                    <constructor-arg name="timeout" value="${redis.timeout}" />
                    <constructor-arg name="name" value="node1" />
                </bean>
                <bean class="redis.clients.jedis.JedisShardInfo">
                    <constructor-arg name="host" value="${redis.host2}" />
                    <constructor-arg name="port" value="${redis.port2}" />
                    <constructor-arg name="timeout" value="${redis.timeout}" />
                    <constructor-arg name="name" value="node2" />
                </bean>
            </list>
        </constructor-arg>
    </bean>

</beans>
3.sentinel模式

仅仅配置了主从复制是不够的,没有sentinel就不能实现故障转移,redis集群就失去意义了。
spring-data-redis对sentinel提供了很好的支持,详细配置如下

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<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>me.com</groupId>
    <artifactId>springmvc</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <spring.version>4.3.0.RELEASE</spring.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.9.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
            <version>2.4.2</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-redis</artifactId>
            <version>1.8.0.RELEASE</version>
        </dependency>
    </dependencies>

</project>

settings.properties

#jedisPoolConfig
redis.maxTotal=50000 
redis.maxIdle=500
redis.minIdle=100
redis.maxWaitMillis=10000 
redis.testOnBorrow=true

#redis-sentinel
redis.sentinel=127.0.0.1:26379
redis.master=mymaster

spring-context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="service,dao,redis"/>


    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>classpath:settings.properties</value>
            </list>
        </property>
    </bean>

    <!-- ******************** Redis Start ******************** -->

    <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <property name="maxTotal" value="${redis.maxTotal}" />
        <property name="maxIdle" value="${redis.maxIdle}" />
        <property name="minIdle" value="${redis.minIdle}" />
        <property name="maxWaitMillis" value="${redis.maxWaitMillis}" />
        <property name="testOnBorrow" value="${redis.testOnBorrow}" />
    </bean>

    <bean id="redisSentinelConfiguration" class="org.springframework.data.redis.connection.RedisSentinelConfiguration">
        <constructor-arg name="master" value="${redis.master}" />
        <constructor-arg name="sentinelHostAndPorts">
            <set>
                <value>${redis.sentinel}</value>
            </set>
        </constructor-arg>
    </bean>

    <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
        <!-- 如有密码可以用p:password指定 -->
        <constructor-arg ref="redisSentinelConfiguration" />
        <constructor-arg ref="jedisPoolConfig" />
    </bean>


    <bean id="stringRedisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate">
        <property name="connectionFactory" ref="jedisConnectionFactory" />
    </bean>

    <bean id="stringRedisSerializer" class="org.springframework.data.redis.serializer.StringRedisSerializer"/>


    <!-- ******************** Redis End ******************** -->

</beans>

TestController

package controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class TestController {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @RequestMapping(value = "test",method = RequestMethod.GET,produces = "application/json;charset=utf-8")
    @ResponseBody
    public String test(){
        stringRedisTemplate.opsForValue().set("key1","v1");
        return stringRedisTemplate.opsForValue().get("key1");
    }

}

另外,特别提醒:
sentinel.conf配置文件中明确说明,需要绑定ip或者解除保护模式(生产环境下建议绑定ip)

# *** IMPORTANT ***
#
# By default Sentinel will not be reachable from interfaces different than
# localhost, either use the 'bind' directive to bind to a list of network
# interfaces, or disable protected mode with "protected-mode no" by
# adding it to this configuration file.
#
# Before doing that MAKE SURE the instance is protected from the outside
# world via firewalling or other means.
#
# For example you may use one of the following:
#
# bind 127.0.0.1 192.168.1.1
#
# protected-mode no

否则会报错:All sentinels down, cannot determine where is mymaster master is running...

4.配置Redis Cluster

Redis Cluster是3.0版本后的一种集群系统,它实现了数据分片,解决了单机数据容量瓶颈问题,同时也实现了高可用。

使用Spring+Jedis配置Redis Cluster也非常简单。

    <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <property name="maxTotal" value="${redis.maxTotal}" />
        <property name="maxIdle" value="${redis.maxIdle}" />
        <property name="minIdle" value="${redis.minIdle}" />
        <property name="maxWaitMillis" value="${redis.maxWaitMillis}" />
        <property name="testOnBorrow" value="${redis.testOnBorrow}" />
    </bean>

    <!--  配置redis cluster -->
    <bean id="redisClusterConfiguration" class="org.springframework.data.redis.connection.RedisClusterConfiguration">
        <property name="clusterNodes">
            <set>
                <bean class="org.springframework.data.redis.connection.RedisNode">
                    <constructor-arg name="host" value="${redis.ip1}"/>
                    <constructor-arg name="port" value="${redis.port1}"/>
                </bean>
                <bean class="org.springframework.data.redis.connection.RedisNode">
                    <constructor-arg name="host" value="${redis.ip2}"/>
                    <constructor-arg name="port" value="${redis.port2}"/>
                </bean>
                <bean class="org.springframework.data.redis.connection.RedisNode">
                    <constructor-arg name="host" value="${redis.ip3}"/>
                    <constructor-arg name="port" value="${redis.port3}"/>
                </bean>
                <bean class="org.springframework.data.redis.connection.RedisNode">
                    <constructor-arg name="host" value="${redis.ip4}"/>
                    <constructor-arg name="port" value="${redis.port4}"/>
                </bean>
                <bean class="org.springframework.data.redis.connection.RedisNode">
                    <constructor-arg name="host" value="${redis.ip5}"/>
                    <constructor-arg name="port" value="${redis.port5}"/>
                </bean>
                <bean class="org.springframework.data.redis.connection.RedisNode">
                    <constructor-arg name="host" value="${redis.ip6}"/>
                    <constructor-arg name="port" value="${redis.port6}"/>
                </bean>
            </set>
        </property>
    </bean>

    <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
        <constructor-arg name="clusterConfig" ref="redisClusterConfiguration" />
        <constructor-arg name="poolConfig" ref="jedisPoolConfig" />
    </bean>

org.springframework.data.redis.connection.RedisClusterConfiguration org.springframework.data.redis.connection.jedis.JedisConnectionFactory 已经为我们封装好了所有的设置,再通过org.springframework.data.redis.core.StringRedisTemplate,就可以在代码中很方便地对Redis进行读写!