spring 项目中使用redis

简要  

  spring对redis做了封装,需要引入的jar包为 spring-data-redis.jar.

  spring-data-redis.1.x.jar跟spring-data-redis.2.x.jar在实现上有所不同。

  本文基于1.8.12与2.x两个版本,分析如何在spring项目中使用、配置redis。

代码实现

  1.8.12版本

    

JedisConnectionFactory类图

    根据JedisConnectionFactory.java类图可以看出,提供了不同入参的构造器,以满足Redis三种模式(单机模式、哨兵模式、集群模式)的连接配置。

    其中:

      JedisConnectionFactory(); 采用默认localhost:6379获取单机模式连接;

      JedisConnectionFactory(JedisPoolConfig poolConfig); 采用localhost:6379获取单机模式连接,并使用自定义连接池配置;

      JedisConnectionFactory(JedisShardInfo shardInfo); shardInfo封装了单机模式连接所需属性以及ssl连接配置;

 

 【上代码】

  单机模式:

@Log4j2
@Service
public class RedisConnectionFactory1 {
    @Value("${spring.data.redis.host}")
    private String redisHost;

    @Value("${spring.data.redis.port}")
    private int redisPort;

    @Value("${spring.data.redis.password}")
    private String redisPassword;

    private StringRedisTemplate redisTemplate;

    @PostConstruct
    public void getJedisConnection(){
     
        JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory();
        jedisConnectionFactory.setHostName(redisHost);
        jedisConnectionFactory.setPort(redisPort);

        //使用连接池配置
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxTotal(20);//连接池最大连接数
        jedisPoolConfig.setMaxIdle(10);//连接池最大空闲数
        jedisConnectionFactory.setPoolConfig(jedisPoolConfig);

        jedisConnectionFactory.setUsePool(true);//可以不写,默认值为true
        jedisConnectionFactory.afterPropertiesSet();//必须有这一步,用来初始化一些默认参数,否则连接会失败

        redisTemplate = new StringRedisTemplate();
        redisTemplate.setConnectionFactory(jedisConnectionFactory);
        redisTemplate.afterPropertiesSet();

    }

    public StringRedisTemplate getRedisTemplate(){
        return this.redisTemplate;
    }
}

   测试代码:

 1 @Log4j2
 2 @RunWith(SpringRunner.class)
 3 @SpringBootTest(classes = ServerApplication.class)
 4 public class RedisConnectionTest {
 5     @Autowired
 6     private RedisService redisService;
 7     @Autowired
 8     private MyRedisConnection myRedisConnection;
 9 
10 
11     public void test1(){
12         RedisConnection connection = myRedisConnection.getRedisTemplate().getConnectionFactory().getConnection();
13 
14         connection.set("test".getBytes(),"value".getBytes());
15 
16         Set<byte[]> keys = connection.keys("*".getBytes());
17 
18         for(byte[] b: keys){
19             System.out.println(new String(b));
20         }
21 
22         System.out.println(new String(connection.get("test".getBytes())));
23 
24     }
25   //多线程测试连接池
26     @Test
27     public void test2(){
28         //启动1000个线程
29         for (int i = 0; i < 100; i++) {
30             ClientThread t = new ClientThread(i);
31             t.start();
32         }
33         try {
34             Thread.sleep(6000);
35         } catch (InterruptedException e) {
36             e.printStackTrace();
37         }
38     }
39 
40     //线程类
41     class ClientThread extends Thread {
42         int i;
43 
44         ClientThread(int i) {
45             this.i = i;
46         }
47 
48         public void run() {
49             RedisConnection connection = myRedisConnection.getRedisTemplate().getConnectionFactory().getConnection();
50             Date date = new Date();
51             SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
52             String time = sdf.format(date);
53             connection.set(("key" + i).getBytes(), time.getBytes());
54             try {
55                 //每次睡眠一个随机时间
56                 Thread.sleep((int) (Math.random() * 5000));
57                 String foo = new String(connection.get(("key" + i).getBytes()));
58                 System.out.println("【输出>>>>】key:" + foo + " 第:" + i + "个线程");
59             } catch (InterruptedException e) {
60                 e.printStackTrace();
61             }finally {
62                 if (connection != null) {
63                     connection.close();
64                 }
65             }
66         }
67     }
  }

  哨兵模式:

    了解哨兵模式之前,需要先了解【主从复制模式】。

    主从复制模式是redis集群模式中的一种,其他两种分别为:哨兵模式、cluster模式。由一个master server + n个slave server构成,slave server启动并连接到master后,会与master完成一次同步过程,master将整个数据库文件传输给slave,slave将接收到数据库文件保存到内存中。自此简单的主从复制模式已经完成,master server可以将客户端的读写请求交给slave server完成,客户端也可以选择进行读写分离,以提高redis的相应效率。

    哨兵模式是基于主从复制模式的,只需要再启动一个redis服务,用来监听master server的服务状态,并在master server宕机后,自动选举一个slave node变为新的master,主从模式就变为哨兵模式。用来监听的redis服务即为“哨兵”。为了整个redis服务的正常运行,我们可以启动多个哨兵进程,以防单个哨兵进程的判断失误情况发生。

@Log4j2
@Service
public class MyRedisConnection {
    @Value("${spring.data.redis.host}")
    private String redisHost;

    @Value("${spring.data.redis.port}")
    private int redisPort;

    @Value("${spring.data.redis.password}")
    private String redisPassword;

    private StringRedisTemplate redisTemplate;

    @PostConstruct
    public void getJedisConnection(){
        log.info("init。。。。");

        /**
         * master server:127.0.0.1:6380
         * slave server1:127.0.0.1:6381
         * slave server2:127.0.0.1:6382
         *
         * sentinel server:127.0.0.1:26381
         * 
         * 将6380kill掉后,客户端不需要切换ip
         */
        Set<String> sentinelNode = Sets.newHashSet();
        sentinelNode.add("127.0.0.1:26381");
        RedisSentinelConfiguration sentinelConfiguration = new RedisSentinelConfiguration("mymaster",sentinelNode);

        //使用连接池配置
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxTotal(20);
        jedisPoolConfig.setMaxIdle(10);

        JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(sentinelConfiguration,jedisPoolConfig);
        jedisConnectionFactory.afterPropertiesSet();//必须有这一步,否则连接会失败

        redisTemplate = new StringRedisTemplate();
        redisTemplate.setConnectionFactory(jedisConnectionFactory);
        redisTemplate.afterPropertiesSet();

    }

    public StringRedisTemplate getRedisTemplate(){
        return this.redisTemplate;
    }
}

   2.0.5版本

      对比1.8.16版本,可以发现,主要的区别是封装类的替换。1.8.16中用来配封装客户端连接配置的JedisShardInfo.java类,被JedisClientConfiguration替换,封装的更加简洁明了。

      在编码上,旧版本中setHostName(String);setPassword(String);setPort(Int)等set方法,在新版本中都是@Deprecated标注的,这就要求我们寻求更佳的实现方法。

      以下,仅用单机+连接池方式为示例:

  

@Log4j2
@Service
public class MyRedisConnection {
    @Value("${spring.data.redis.host}")
    private String redisHost;

    @Value("${spring.data.redis.port}")
    private int redisPort;

    @Value("${spring.data.redis.password}")
    private String redisPassword;

    private StringRedisTemplate redisTemplate;

    @PostConstruct
    public void getJedisConnection(){
        log.info("init。。。。");

        RedisStandaloneConfiguration standaloneConfiguration = new RedisStandaloneConfiguration(redisHost,redisPort);
        /**使用连接池配置。
         *
         * 为了获取一个单机+连接池的redis,只能通过JedisConnectionFactory(standaloneConfiguration,jedisClientConfiguration);这个构造器
         * 现在就要想方设法实例化JedisClientConfiguration对象
         */
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxTotal(20);
        jedisPoolConfig.setMaxIdle(10);

        /**
         * 非常复杂!!!并且通过强转得到的JedisPoolingClientConfigurationBuilder对象,其实是很不规范的
         *
         * 因为JedisClientConfiguration.builder();返回的是JedisClientConfigurationBuilder类型,
         * 之所以能强转是因为方法内返回的是DefaultJedisClientConfigurationBuilder类型,
         * 而DefaultJedisClientConfigurationBuilder同时实现了JedisClientConfigurationBuilder、JedisPoolingClientConfigurationBuilder两个接口
         */
        JedisClientConfiguration.JedisPoolingClientConfigurationBuilder jpcb =
                (JedisClientConfiguration.JedisPoolingClientConfigurationBuilder)JedisClientConfiguration.builder();
        jpcb.poolConfig(jedisPoolConfig);
        JedisClientConfiguration jedisClientConfiguration = jpcb.build();

        //
        JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(standaloneConfiguration,jedisClientConfiguration);


        redisTemplate = new StringRedisTemplate();
        redisTemplate.setConnectionFactory(jedisConnectionFactory);
        redisTemplate.afterPropertiesSet();

    }

    public StringRedisTemplate getRedisTemplate(){
        return this.redisTemplate;
    }
}

 

 

  

  

posted @ 2019-01-16 14:58  meama  阅读(766)  评论(0编辑  收藏  举报