简要
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连接配置;
【上代码】
单机模式:
1 |
<span>@Log4j2 @Service </span><span>public</span> <span>class</span><span> RedisConnectionFactory1 { @Value(</span>"${spring.data.redis.host}"<span>) </span><span>private</span><span> String redisHost; @Value(</span>"${spring.data.redis.port}"<span>) </span><span>private</span> <span>int</span><span> redisPort; @Value(</span>"${spring.data.redis.password}"<span>) </span><span>private</span><span> String redisPassword; </span><span>private</span><span> StringRedisTemplate redisTemplate; @PostConstruct </span><span>public</span> <span>void</span><span> getJedisConnection(){ JedisConnectionFactory jedisConnectionFactory </span>= <span>new</span><span> JedisConnectionFactory(); jedisConnectionFactory.setHostName(redisHost); jedisConnectionFactory.setPort(redisPort); </span><span>//</span><span>使用连接池配置</span> JedisPoolConfig jedisPoolConfig = <span>new</span><span> JedisPoolConfig(); jedisPoolConfig.setMaxTotal(</span>20);<span>//</span><span>连接池最大连接数</span> jedisPoolConfig.setMaxIdle(10);<span>//</span><span>连接池最大空闲数</span> <span> jedisConnectionFactory.setPoolConfig(jedisPoolConfig); jedisConnectionFactory.setUsePool(</span><span>true</span>);<span>//</span><span>可以不写,默认值为true</span> jedisConnectionFactory.afterPropertiesSet();<span>//</span><span>必须有这一步,用来初始化一些默认参数,否则连接会失败</span> <span> redisTemplate </span>= <span>new</span><span> StringRedisTemplate(); redisTemplate.setConnectionFactory(jedisConnectionFactory); redisTemplate.afterPropertiesSet(); } </span><span>public</span><span> StringRedisTemplate getRedisTemplate(){ </span><span>return</span> <span>this</span><span>.redisTemplate; } }</span> |
测试代码:
1 |
<span> 1</span> <span>@Log4j2 </span><span> 2</span> @RunWith(SpringRunner.<span>class</span><span>) </span><span> 3</span> @SpringBootTest(classes = ServerApplication.<span>class</span><span>) </span><span> 4</span> <span>public</span> <span>class</span><span> RedisConnectionTest { </span><span> 5</span> <span> @Autowired </span><span> 6</span> <span>private</span><span> RedisService redisService; </span><span> 7</span> <span> @Autowired </span><span> 8</span> <span>private</span><span> MyRedisConnection myRedisConnection; </span><span> 9</span> <span>10</span> <span>11</span> <span>public</span> <span>void</span><span> test1(){ </span><span>12</span> RedisConnection connection =<span> myRedisConnection.getRedisTemplate().getConnectionFactory().getConnection(); </span><span>13</span> <span>14</span> connection.set("test".getBytes(),"value"<span>.getBytes()); </span><span>15</span> <span>16</span> Set<<span>byte</span>[]> keys = connection.keys("*"<span>.getBytes()); </span><span>17</span> <span>18</span> <span>for</span>(<span>byte</span><span>[] b: keys){ </span><span>19</span> System.out.println(<span>new</span><span> String(b)); </span><span>20</span> <span> } </span><span>21</span> <span>22</span> System.out.println(<span>new</span> String(connection.get("test"<span>.getBytes()))); </span><span>23</span> <span>24</span> <span> } </span><span>25</span> //多线程测试连接池 <span>26</span> <span> @Test </span><span>27</span> <span>public</span> <span>void</span><span> test2(){ </span><span>28</span> <span>//</span><span>启动1000个线程</span> <span>29</span> <span>for</span> (<span>int</span> i = 0; i < 100; i++<span>) { </span><span>30</span> ClientThread t = <span>new</span><span> ClientThread(i); </span><span>31</span> <span> t.start(); </span><span>32</span> <span> } </span><span>33</span> <span>try</span><span> { </span><span>34</span> Thread.sleep(6000<span>); </span><span>35</span> } <span>catch</span><span> (InterruptedException e) { </span><span>36</span> <span> e.printStackTrace(); </span><span>37</span> <span> } </span><span>38</span> <span> } </span><span>39</span> <span>40</span> <span>//</span><span>线程类</span> <span>41</span> <span>class</span> ClientThread <span>extends</span><span> Thread { </span><span>42</span> <span>int</span><span> i; </span><span>43</span> <span>44</span> ClientThread(<span>int</span><span> i) { </span><span>45</span> <span>this</span>.i =<span> i; </span><span>46</span> <span> } </span><span>47</span> <span>48</span> <span>public</span> <span>void</span><span> run() { </span><span>49</span> RedisConnection connection =<span> myRedisConnection.getRedisTemplate().getConnectionFactory().getConnection(); </span><span>50</span> Date date = <span>new</span><span> Date(); </span><span>51</span> SimpleDateFormat sdf = <span>new</span> SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS"<span>); </span><span>52</span> String time =<span> sdf.format(date); </span><span>53</span> connection.set(("key" +<span> i).getBytes(), time.getBytes()); </span><span>54</span> <span>try</span><span> { </span><span>55</span> <span>//</span><span>每次睡眠一个随机时间</span> <span>56</span> Thread.sleep((<span>int</span>) (Math.random() * 5000<span>)); </span><span>57</span> String foo = <span>new</span> String(connection.get(("key" +<span> i).getBytes())); </span><span>58</span> System.out.println("【输出>>>>】key:" + foo + " 第:" + i + "个线程"<span>); </span><span>59</span> } <span>catch</span><span> (InterruptedException e) { </span><span>60</span> <span> e.printStackTrace(); </span><span>61</span> }<span>finally</span><span> { </span><span>62</span> <span>if</span> (connection != <span>null</span><span>) { </span><span>63</span> <span> connection.close(); </span><span>64</span> <span> } </span><span>65</span> <span> } </span><span>66</span> <span> } </span><span>67</span> }<br> } |
哨兵模式:
了解哨兵模式之前,需要先了解【主从复制模式】。
主从复制模式是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服务的正常运行,我们可以启动多个哨兵进程,以防单个哨兵进程的判断失误情况发生。
1 |
<span>@Log4j2 @Service </span><span>public</span> <span>class</span><span> MyRedisConnection { @Value(</span>"${spring.data.redis.host}"<span>) </span><span>private</span><span> String redisHost; @Value(</span>"${spring.data.redis.port}"<span>) </span><span>private</span> <span>int</span><span> redisPort; @Value(</span>"${spring.data.redis.password}"<span>) </span><span>private</span><span> String redisPassword; </span><span>private</span><span> StringRedisTemplate redisTemplate; @PostConstruct </span><span>public</span> <span>void</span><span> getJedisConnection(){ log.info(</span>"init。。。。"<span>); </span><span>/**</span><span> * 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 </span><span>*/</span><span> Set</span><String> sentinelNode =<span> Sets.newHashSet(); sentinelNode.add(</span>"127.0.0.1:26381"<span>); RedisSentinelConfiguration sentinelConfiguration </span>= <span>new</span> RedisSentinelConfiguration("mymaster"<span>,sentinelNode); </span><span>//</span><span>使用连接池配置</span> JedisPoolConfig jedisPoolConfig = <span>new</span><span> JedisPoolConfig(); jedisPoolConfig.setMaxTotal(</span>20<span>); jedisPoolConfig.setMaxIdle(</span>10<span>); JedisConnectionFactory jedisConnectionFactory </span>= <span>new</span><span> JedisConnectionFactory(sentinelConfiguration,jedisPoolConfig); jedisConnectionFactory.afterPropertiesSet();</span><span>//</span><span>必须有这一步,否则连接会失败</span> <span> redisTemplate </span>= <span>new</span><span> StringRedisTemplate(); redisTemplate.setConnectionFactory(jedisConnectionFactory); redisTemplate.afterPropertiesSet(); } </span><span>public</span><span> StringRedisTemplate getRedisTemplate(){ </span><span>return</span> <span>this</span><span>.redisTemplate; } }</span> |
2.0.5版本
对比1.8.16版本,可以发现,主要的区别是封装类的替换。1.8.16中用来配封装客户端连接配置的JedisShardInfo.java类,被JedisClientConfiguration替换,封装的更加简洁明了。
在编码上,旧版本中setHostName(String);setPassword(String);setPort(Int)等set方法,在新版本中都是@Deprecated标注的,这就要求我们寻求更佳的实现方法。
以下,仅用单机+连接池方式为示例:
1 |
<span>@Log4j2 @Service </span><span>public</span> <span>class</span><span> MyRedisConnection { @Value(</span>"${spring.data.redis.host}"<span>) </span><span>private</span><span> String redisHost; @Value(</span>"${spring.data.redis.port}"<span>) </span><span>private</span> <span>int</span><span> redisPort; @Value(</span>"${spring.data.redis.password}"<span>) </span><span>private</span><span> String redisPassword; </span><span>private</span><span> StringRedisTemplate redisTemplate; @PostConstruct </span><span>public</span> <span>void</span><span> getJedisConnection(){ log.info(</span>"init。。。。"<span>); RedisStandaloneConfiguration standaloneConfiguration </span>= <span>new</span><span> RedisStandaloneConfiguration(redisHost,redisPort); </span><span>/**</span><span>使用连接池配置。 * * 为了获取一个单机+连接池的redis,只能通过JedisConnectionFactory(standaloneConfiguration,jedisClientConfiguration);这个构造器 * 现在就要想方设法实例化JedisClientConfiguration对象 </span><span>*/</span><span> JedisPoolConfig jedisPoolConfig </span>= <span>new</span><span> JedisPoolConfig(); jedisPoolConfig.setMaxTotal(</span>20<span>); jedisPoolConfig.setMaxIdle(</span>10<span>); </span><span>/**</span><span> * 非常复杂!!!并且通过强转得到的JedisPoolingClientConfigurationBuilder对象,其实是很不规范的 * * 因为JedisClientConfiguration.builder();返回的是JedisClientConfigurationBuilder类型, * 之所以能强转是因为方法内返回的是DefaultJedisClientConfigurationBuilder类型, * 而DefaultJedisClientConfigurationBuilder同时实现了JedisClientConfigurationBuilder、JedisPoolingClientConfigurationBuilder两个接口 </span><span>*/</span><span> JedisClientConfiguration.JedisPoolingClientConfigurationBuilder jpcb </span>=<span> (JedisClientConfiguration.JedisPoolingClientConfigurationBuilder)JedisClientConfiguration.builder(); jpcb.poolConfig(jedisPoolConfig); JedisClientConfiguration jedisClientConfiguration </span>=<span> jpcb.build(); </span><span>// </span> JedisConnectionFactory jedisConnectionFactory = <span>new</span><span> JedisConnectionFactory(standaloneConfiguration,jedisClientConfiguration); redisTemplate </span>= <span>new</span><span> StringRedisTemplate(); redisTemplate.setConnectionFactory(jedisConnectionFactory); redisTemplate.afterPropertiesSet(); } </span><span>public</span><span> StringRedisTemplate getRedisTemplate(){ </span><span>return</span> <span>this</span><span>.redisTemplate; } }</span> |