spring實戰4 spring整合redis哨兵
阿新 • • 發佈:2019-02-18
前言
開始
建專案
新建spring-redis-sentinel web專案
導包
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId> spring-data-redis</artifactId>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId >
</dependency>
<!--自己封裝的增刪改查包-->
<dependency>
<groupId>com.hsy.java</groupId>
<artifactId>java-util</artifactId>
</dependency>
配置檔案
新建redis.properties
#訪問地址 redis中心
redis.host=172.16.191.102
# redis.host=192.168.1.106
#訪問埠
redis.port=6379
#授權密碼,有沒有這一項取決於要連線的redis服務是否設定了此項
redis.auth=123456
redis.dbIndex=0
redis.timeout=100000
# redis哨兵資訊
redis.sentinel.node1.host=172.16.191.102
redis.sentinel.node1.port=26379
redis.sentinel.node2.host=172.16.191.102
redis.sentinel.node2.port=26380
redis.sentinel.node3.host=172.16.191.102
redis.sentinel.node3.port=26381
redis.pool.maxTotal=200
#連線池的最大資料庫連線數。設為0表示無限制
redis.pool.maxIdle=1024
redis.pool.minIdle=8
#在borrow一個jedis例項時,是否提前進行validate操作;如果為true,則得到的jedis例項均是可用的;
redis.pool.testOnCreate=true
redis.pool.testOnBorrow=true
redis.pool.testOnReturn=true
#Idle時進行連線掃描
redis.pool.testWhileIdle=true
redis.pool.maxWaitMillis=100000
#表示idle object evitor兩次掃描之間要sleep的毫秒數
redis.pool.timeBetweenEvictionRunsMillis=30000
#表示idle object evitor每次掃描的最多的物件數
redis.pool.numTestsPerEvictionRun=10
#表示一個物件至少停留在idle狀態的最短時間,然後才能被idle object evitor掃描並驅逐;
# 這一項只有在timeBetweenEvictionRunsMillis大於0時才有意義
redis.pool.minEvictableIdleTimeMillis=60000
新建spring配置檔案
<?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:property-placeholder location="classpath:config/redis.properties" ignore-resource-not-found="true"/>
<!--<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:properties/redis.properties</value>
</list>
</property>
</bean>-->
<!-- redis config start -->
<!-- 配置JedisPoolConfig例項 -->
<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxTotal" value="${redis.pool.maxTotal}"/>
<property name="maxIdle" value="${redis.pool.maxIdle}"/>
<property name="minIdle" value="${redis.pool.minIdle}"/>
<property name="testOnCreate" value="${redis.pool.testOnCreate}"/>
<property name="testOnBorrow" value="${redis.pool.testOnBorrow}"/>
<property name="testOnReturn" value="${redis.pool.testOnReturn}"/>
<property name="testWhileIdle" value="${redis.pool.testWhileIdle}"/>
<property name="maxWaitMillis" value="${redis.pool.maxWaitMillis}"/>
<property name="timeBetweenEvictionRunsMillis" value="${redis.pool.timeBetweenEvictionRunsMillis}"/>
<property name="numTestsPerEvictionRun" value="${redis.pool.numTestsPerEvictionRun}"/>
<property name="minEvictableIdleTimeMillis" value="${redis.pool.minEvictableIdleTimeMillis}"/>
</bean>
<!-- 配置JedisConnectionFactory -->
<bean id="jedisConnectionFactory"
class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<property name="hostName" value="${redis.host}"/>
<property name="port" value="${redis.port}"/>
<property name="password" value="${redis.auth}"/>
<property name="database" value="${redis.dbIndex}"/>
<property name="timeout" value="${redis.timeout}"/>
<property name="poolConfig" ref="poolConfig"/>
</bean>
<bean id="redisSentinelConfiguration" class="org.springframework.data.redis.connection.RedisSentinelConfiguration">
<property name="sentinels">
<set>
<bean name="sentinelNode1" class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host" value="${redis.sentinel.node1.host}"/>
<constructor-arg name="port" value="${redis.sentinel.node1.port}"/>
</bean>
<bean name="sentinelNode2" class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host" value="${redis.sentinel.node2.host}"/>
<constructor-arg name="port" value="${redis.sentinel.node2.port}"/>
</bean>
<bean name="sentinelNode3" class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host" value="${redis.sentinel.node3.host}"/>
<constructor-arg name="port" value="${redis.sentinel.node3.port}"/>
</bean>
</set>
</property>
<property name="master">
<bean name="masterNode" class="org.springframework.data.redis.connection.RedisNode">
<!--必須指定主節點名稱-->
<property name="name" value="mymaster"/>
<!--
<constructor-arg name="host" value="${redis.host}"/>
<constructor-arg name="port" value="6379"/>
-->
</bean>
</property>
</bean>
<!--哨兵配置方式二-->
<!--
<bean id="redisSentinelConfiguration" class="org.springframework.data.redis.connection.RedisSentinelConfiguration">
<constructor-arg name="propertySource" ref="propertySource"/>
</bean>
<bean name="propertySource" class="org.springframework.core.io.support.ResourcePropertySource">
<constructor-arg name="location" value="classpath:spring-redis-sentinel.properties" />
</bean>
-->
<!--
使用JDK提供的序列化功能。 優點是反序列化時不需要提供型別資訊(class),但缺點是序列化後的結果非常龐大,是JSON格式的5倍左右,這樣就會消耗redis伺服器的大量記憶體。
-->
<bean id="stringKeySerializer" class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
<!--
JdkSerializationRedisSerializer,這個序列化方法是Idk提供的,
要求要被序列化的類繼承自Serializeable介面,然後通過Jdk物件序列化的方法儲存,
這個序列化儲存的物件,即使是個String型別的,在redis控制檯,也是看不出來的,
因為它儲存了一些物件的型別什麼的額外資訊。
-->
<bean id="jdkSerializationRedisSerializer"
class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/>
<bean id="genericJackson2JsonRedisSerializer"
class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer"/>
<!--
使用Jackson庫將物件序列化為JSON字串。優點是速度快,序列化後的字串短小精悍。
但缺點也非常致命,那就是此類的建構函式中有一個型別引數,必須提供要序列化物件的型別資訊(.class物件)。
通過檢視原始碼,發現其只在反序列化過程中用到了型別資訊。
-->
<!--<bean id="jackson2JsonRedisSerializer" class="org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer">
<constructor-arg type="java.lang.Object" ></constructor-arg>
</bean>-->
<!-- 配置RedisTemplate -->
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="jedisConnectionFactory"/>
<!-- 如果不配置Serializer,那麼儲存的時候只能使用String,如果用物件型別儲存,那麼會提示錯誤 can't cast to String!!!-->
<property name="keySerializer" ref="stringKeySerializer"/>
<property name="hashKeySerializer" ref="stringKeySerializer"/>
<property name="valueSerializer" ref="genericJackson2JsonRedisSerializer"/>
<property name="hashValueSerializer" ref="genericJackson2JsonRedisSerializer"/>
</bean>
<!-- 配置StringRedisTemplate 下面的各種key都是stringKeySerializer序列化方式-->
<bean id="stringRedisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate">
<property name="connectionFactory" ref="jedisConnectionFactory"/>
</bean>
<!-- redis config end -->
</beans>
crud
新建dao層crud方法,此處引用的是個人封裝好的增刪改查方法,在不貼上。
@Repository(value = "redisRepository")
public class RedisRepository extends AbstractSpringRedisCacheEnhance {
@Autowired
RedisTemplate<String, Object> redisTemplate;
@Override
public StringRedisTemplate getStringRedisTemplate() {
return null;
}
@Override
public RedisTemplate<String, Object> getRedisTemplate() {
return redisTemplate;
}
}
測試
新建測試類
package com.hsy.spring.redis.dao;
import com.hsy.spring.redis.sentinel.dao.RedisRepository;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* @author heshiyuan
* @description <p></p>
* @path spring/com.hsy.spring.redis.dao
* @date 2018/7/23 18:42
* @github http://github.com/shiyuan2he
* @email [email protected]
* Copyright (c) 2018 [email protected] All rights reserved.
* @price ¥5 微信:hewei1109
*/
@SuppressWarnings("Duplicates")
@RunWith(SpringRunner.class)
@ContextConfiguration({"classpath*:/spring/applicationContext.xml"})
public class RedisRepositoryTest {
private Logger logger = LoggerFactory.getLogger(getClass());
@Autowired private RedisRepository redisRepository;
public Map<String, Object> generateMap(){
Map<String, Object> returnMap = new HashMap<>();
returnMap.put("aa", "aa");
Map<String, Object> innerMap = new HashMap<>();
innerMap.put("ss", 3);
innerMap.put("rr",false);
innerMap.put("tt","中文");
returnMap.put("bb", innerMap);
returnMap.put("cc", 1.000);
returnMap.put("dd", true);
returnMap.put("ee", 1);
return returnMap;
}
public List<Map<String, Object>> generateList(){
List<Map<String, Object>> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
list.add(generateMap());
}
return list;
}
@Test
public void clear(){
redisRepository.clear();
}
@Test
public void testSet(){
redisRepository.valueSet("name", "robot");
redisRepository.valueSet("name2", "robot", 1600, TimeUnit.SECONDS);
redisRepository.valueSet("set:map", generateMap());
redisRepository.valueSet("set:map", generateMap(), 1600, TimeUnit.SECONDS);
redisRepository.valueSet("set:list", generateList());
redisRepository.valueSet("set:list", generateList(), 1600, TimeUnit.SECONDS);
}
@Test
public void testDelete(){
//redisRepository.delete("name2", true);
redisRepository.delete("name", false);
}
@Test
public void testGet(){
logger.info("{}", redisRepository.valueGet("name", false));
logger.info("{}", redisRepository.valueGet("name2", true));
logger.info("{}", redisRepository.valueGet("set:map", false));
logger.info("{}", redisRepository.valueGet("set:map", true));
logger.info("{}", redisRepository.valueGet("set:list", false));
logger.info("{}", redisRepository.valueGet("set:list", true));
//logger.info("{}", redisRepository.getAndSet("name", "new value",false));
//logger.info("{}", redisRepository.getAndSet("name", "new value",true));
}
@Test
public void testIncrement(){
for (int i = 0; i < 10; i++) {
logger.info("{}", redisRepository.valueIncrement("mobile:15911111111", 1l, 60, TimeUnit.MINUTES));
logger.info("{}", redisRepository.valueIncrement("tel:15911111111", 1.0, 70, TimeUnit.MINUTES));
}
}
@Test
public void testSetArray(){
for (int i = 0; i < 10; i++) {
logger.info("{}", redisRepository.setAdd("set:array1",i));
}
for (int i = 5; i < 20; i++) {
logger.info("{}", redisRepository.setAdd("set:array1",i));
logger.info("{}", redisRepository.setAdd("set:array2",i));
}
//logger.info("{}", redisRepository.setPop("set:array"));
logger.info("{}", redisRepository.setDifference("set:array1","set:array2"));
logger.info("{}", redisRepository.setDifferenceAndStore("set:array1","set:array2", "set:array3"));
logger.info("{}", redisRepository.setAdd("set:add:map",generateMap()));
logger.info("{}", redisRepository.setAdd("set:add:list",generateList()));
logger.info("{}", redisRepository.setPop("set:add:map"));
logger.info("{}", redisRepository.setPop("set:add:list"));
}
@Test
public void testList(){
for (int i = 0; i < 10; i++) {
logger.info("{}", redisRepository.listLeftPush("list:lilo:list", generateList()));
logger.info("{}", redisRepository.listLeftPush("list:liro:list", generateList()));
logger.info("{}", redisRepository.listRightPush("list:rilo:list", generateList()));
logger.info("{}", redisRepository.listRightPush("list:riro:list", generateList()));
}
for (int i = 0; i < 5; i++) {
logger.info("{}", redisRepository.listLeftPop("list:lilo:list"));
logger.info("{}", redisRepository.listRightPop("list:liro:list"));
logger.info("{}", redisRepository.listLeftPop("list:rilo:list"));
logger.info("{}", redisRepository.listRightPop("list:riro:list"));
}
for (int i = 0; i < 10; i++) {
logger.info("{}", redisRepository.listLeftPush("list:lilo:map", generateMap()));
logger.info("{}", redisRepository.listLeftPush("list:liro:map", generateMap()));
logger.info("{}", redisRepository.listRightPush("list:rilo:map", generateMap()));
logger.info("{}", redisRepository.listRightPush("list:riro:map", generateMap()));
}
for (int i = 0; i < 5; i++) {
logger.info("{}", redisRepository.listLeftPop("list:lilo:map"));
logger.info("{}", redisRepository.listRightPop("list:liro:map"));
logger.info("{}", redisRepository.listLeftPop("list:rilo:map"));
logger.info("{}", redisRepository.listRightPop("list:riro:map"));
}
}
@Test
public void testZSet(){
for (int i = 0; i < 10; i++) {
logger.info("{}", redisRepository.zSetAdd("zset:map", generateMap(), i));
}
redisRepository.zSetIncrementScore("zset:Map", "4", 30);
}
@Test
public void testHash(){
for (int i = 0; i < 10; i++) {
redisRepository.hashPut("hash:map", String.valueOf(i), generateMap());
logger.info("{}", redisRepository.hashGet("hash:map", String.valueOf(i)));
}
for (int i = 0; i < 10; i++) {
redisRepository.hashPut("hash:list", String.valueOf(i), generateList());
logger.info("{}", redisRepository.hashGet("hash:list", String.valueOf(i)));
}
}
}
總結
按照以上操作即可完成spring整合redis哨兵模式,簡單而簡潔。哨兵模式對於伺服器防災上有很好的可用性,保證服務
健壯可用,方式因伺服器故障導致網站快取穿透而致網站執行不暢。是單例redis基礎之上的一個升級方案。