Spring Boot整合Redis的完整步驟
前言
實際 開發(fā) 中 緩存 處理是必須的,不可能我們每次客戶端去請求一次 服務器 ,服務器每次都要去 數(shù)據(jù)庫 中進行查找,為什么要使用緩存?說到底是為了提高系統(tǒng)的運行速度。將用戶頻繁訪問的內容存放在離用戶最近,訪問速度最 快的 地方,提高用戶的響 應速度,今天先來講下在 springboot 中整合 redis 的詳細步驟。
一、Spring Boot對Redis的支持
Spring對Redis的支持是使用Spring Data Redis來實現(xiàn)的,一般使用Jedis或者lettuce(默認),Java客戶端在 org.springframework.boot.autoconfigure.data.redis(Spring Boot 2.x) 中redis的自動配置 AutoConfigureDataRedis
RedisAutoConfiguration提供了RedisTemplate與StringRedisTemplate(只針對鍵值都是字符型的數(shù)據(jù))模板,其中注解 @ConditionalOnMissingBean 是關鍵,表明該Bean如果在Spring中已經(jīng)存在,則忽略,如果沒有存在則在此處注冊由Spring管理,也就是說我們可以“重寫”該bean,實現(xiàn)自己的RedisTemplate與StringRedisTemplate,事實上,是要需要重寫的,理由如下:
- 沒有實現(xiàn)我們所需要的序列化;
- 泛型總是<Object, Object>,大部分場景我們更需要<String, Object>。
@Bean
@ConditionalOnMissingBean(
name = {"redisTemplate"}
)
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
RedisTemplate<Object, Object> template = new RedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
@Bean
@ConditionalOnMissingBean
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
二、實戰(zhàn)
1、添加依賴
1)需要spring-boot-starter-cache依賴,管理緩存
<!-- Spring Boot Cache --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> </dependency>
2)需要spring-boot-starter-data-redis依賴(注:spring boot 2.x改為在data下),支持redis:主要以為Jedis客戶端為主,排除默認的lettuce作為客戶端的依賴
<!-- Redis Cache -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<!-- 排除lettuce包,使用jedis代替-->
<exclusions>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
3)需要jedis-client依賴(注:Redis Client 3版本以上會報錯與spring-boot-starter-data-redis沖突,最好使用2.9.x),使用jedis作為客戶端
<!-- Redis Client 3版本以上會報錯與spring-boot-starter-data-redis沖突 --> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.9.0</version> </dependency>
2、redis配置
創(chuàng)建RedisConfig配置類,增加@Configuration注解,同時開啟緩存管理支持(添加注解@EnableCaching),繼承CachingConfigurerSupport重寫key生成策略
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
/**
* 生成key的策略:根據(jù)類名+方法名+所有參數(shù)的值生成唯一的一個key
* @return
*/
@Bean
@Override
public KeyGenerator keyGenerator() {
return (Object target, Method method, Object... params) -> {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getName());
sb.append(method.getName());
for (Object obj : params) {
sb.append(obj.toString());
}
return sb.toString();
};
}
}
之后使用的application.yml配置文件,其中這里已經(jīng)選擇jedis作為客戶端。
# redis 配置
redis:
port: 6379
# Redis服務器連接密碼(默認為空)
password:
host: xxx.xxx.xxx.xxx
database: 0
jedis:
pool:
#連接池最大連接數(shù)(使用負值表示沒有限制)
max-active: 300
# 連接池中的最小空閑連接
max-idle: 100
# 連接池最大阻塞等待時間(使用負值表示沒有限制)
max-wait: 10000
# 連接超時時間(毫秒)
timeout: 5000
同時讀取配置屬性,注入JedisPoolConfig
/**
* redis配置屬性讀取
*/
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private int port;
@Value("${spring.redis.database}")
private int database;
@Value("${spring.redis.jedis.pool.max-idle}")
private int maxIdle;
@Value("${spring.redis.jedis.pool.max-wait}")
private long maxWaitMillis;
@Value("${spring.redis.jedis.pool.max-active}")
private int maxActive;
/**
* JedisPoolConfig配置
* @return
*/
@Bean
public JedisPoolConfig jedisPoolConfig() {
log.info("初始化JedisPoolConfig");
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxTotal(maxActive);
jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);
jedisPoolConfig.setMaxIdle(maxIdle);
return jedisPoolConfig;
}
3、實現(xiàn)序列化
針對RedisTemplate或StringRedisTemplate進行序列化,同時重寫注冊Bean
RedisTemplate默認使用JdkSerializationRedisSerializer,StringRedisTmeplate默認使用的是StringRedisSerializer。但都是不符合實際要求的
/**
* 重新實現(xiàn)RedisTemplate:解決序列化問題
* @param redisConnectionFactory
* @return
*/
@Bean
@SuppressWarnings({"rawtype", "unchecked"})
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
RedisTemplate<String, Object> template = new RedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
// 設置任何字段可見
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// 設置不是final的屬性可以轉換
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
log.info("objectMapper: {}", om);
jackson2JsonRedisSerializer.setObjectMapper(om);
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
// hash的key采用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
// value序列化方式采用jackson序列化方式
template.setValueSerializer(jackson2JsonRedisSerializer);
// hash的value序列化方式采用jackson序列化方式
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
template.setEnableTransactionSupport(true);
return template;
}
/**
* 重新實現(xiàn)StringRedisTmeplate:鍵值都是String的的數(shù)據(jù)
* @param redisConnectionFactory
* @return
*/
@Bean
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
StringRedisTemplate template = new StringRedisTemplate();
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
template.setConnectionFactory(redisConnectionFactory);
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
// hash的key采用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
// value序列化方式采用jackson序列化方式
template.setValueSerializer(jackson2JsonRedisSerializer);
// hash的value序列化方式采用jackson序列化方式
template.setHashValueSerializer(jackson2JsonRedisSerializer);
return template;
}
4、創(chuàng)建Redis連接工廠,同時注冊Bean
注意Spring Boot 1.x與Spring Boot 2.x的區(qū)別,已在代碼中注釋表明,Spring Boot 1.x使用的是JedisConnectionFactory 。而Spring Boot 2.x使用的是RedisStandaloneConfiguration ,之后傳入JedisConnectionFactory返回Bean
/**
* 注入RedisConnectionFactory
* @return
*/
@Bean
public RedisConnectionFactory redisConnectionFactory(JedisPoolConfig jedisPoolConfig) {
log.info("初始化JedisConnectionFactory");
/* 在Spring Boot 1.x中已經(jīng)過時,采用RedisStandaloneConfiguration配置
JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(jedisPoolConfig);
jedisConnectionFactory.setHostName(host);
jedisConnectionFactory.setDatabase(database);*/
// JedisConnectionFactory配置hsot、database、password等參數(shù)
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
redisStandaloneConfiguration.setHostName(host);
redisStandaloneConfiguration.setPort(port);
redisStandaloneConfiguration.setDatabase(database);
// JedisConnectionFactory配置jedisPoolConfig
JedisClientConfiguration.JedisPoolingClientConfigurationBuilder jedisPoolConfigBuilder =
(JedisClientConfiguration.JedisPoolingClientConfigurationBuilder)JedisClientConfiguration.builder();
jedisPoolConfigBuilder.poolConfig(jedisPoolConfig);
return new JedisConnectionFactory(redisStandaloneConfiguration);
}
5、完整的RedisConfig配置類
/**
*
* @author jian
* @date 2019/4/14
* @description
* 1) RedisTemplate(或StringRedisTemplate)雖然已經(jīng)自動配置,但是不靈活(第一沒有序列化,第二泛型為<Object, Object>不是我們想要的類型)
* 所以自己實現(xiàn)RedisTemplate或StringRedisTemplate)
* 2) 采用RedisCacheManager作為緩存管理器
*
*/
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
private static final Logger log = LoggerFactory.getLogger(RedisConfig.class);
/**
* redis配置屬性讀取
*/
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private int port;
@Value("${spring.redis.database}")
private int database;
@Value("${spring.redis.jedis.pool.max-idle}")
private int maxIdle;
@Value("${spring.redis.jedis.pool.max-wait}")
private long maxWaitMillis;
@Value("${spring.redis.jedis.pool.max-active}")
private int maxActive;
/**
* JedisPoolConfig配置
* @return
*/
@Bean
public JedisPoolConfig jedisPoolConfig() {
log.info("初始化JedisPoolConfig");
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxTotal(maxActive);
jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);
jedisPoolConfig.setMaxIdle(maxIdle);
return jedisPoolConfig;
}
/**
* 注入RedisConnectionFactory
* @return
*/
@Bean
public RedisConnectionFactory redisConnectionFactory(JedisPoolConfig jedisPoolConfig) {
log.info("初始化JedisConnectionFactory");
/* 在Spring Boot 1.x中已經(jīng)過時,采用RedisStandaloneConfiguration配置
JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(jedisPoolConfig);
jedisConnectionFactory.setHostName(host);
jedisConnectionFactory.setDatabase(database);*/
// JedisConnectionFactory配置hsot、database、password等參數(shù)
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
redisStandaloneConfiguration.setHostName(host);
redisStandaloneConfiguration.setPort(port);
redisStandaloneConfiguration.setDatabase(database);
// JedisConnectionFactory配置jedisPoolConfig
JedisClientConfiguration.JedisPoolingClientConfigurationBuilder jedisPoolConfigBuilder =
(JedisClientConfiguration.JedisPoolingClientConfigurationBuilder)JedisClientConfiguration.builder();
jedisPoolConfigBuilder.poolConfig(jedisPoolConfig);
return new JedisConnectionFactory(redisStandaloneConfiguration);
}
/**
* 采用RedisCacheManager作為緩存管理器
* @param connectionFactory
*/
@Bean
public CacheManager cacheManager(RedisConnectionFactory connectionFactory) {
RedisCacheManager redisCacheManager = RedisCacheManager.create(connectionFactory);
return redisCacheManager;
}
/**
* 生成key的策略:根據(jù)類名+方法名+所有參數(shù)的值生成唯一的一個key
* @return
*/
@Bean
@Override
public KeyGenerator keyGenerator() {
return (Object target, Method method, Object... params) -> {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getName());
sb.append(method.getName());
for (Object obj : params) {
sb.append(obj.toString());
}
return sb.toString();
};
}
/**
* 重新實現(xiàn)RedisTemplate:解決序列化問題
* @param redisConnectionFactory
* @return
*/
@Bean
@SuppressWarnings({"rawtype", "unchecked"})
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
RedisTemplate<String, Object> template = new RedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
// 設置任何字段可見
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// 設置不是final的屬性可以轉換
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
log.info("objectMapper: {}", om);
jackson2JsonRedisSerializer.setObjectMapper(om);
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
// hash的key采用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
// value序列化方式采用jackson序列化方式
template.setValueSerializer(jackson2JsonRedisSerializer);
// hash的value序列化方式采用jackson序列化方式
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
template.setEnableTransactionSupport(true);
return template;
}
/**
* 重新實現(xiàn)StringRedisTmeplate:鍵值都是String的的數(shù)據(jù)
* @param redisConnectionFactory
* @return
*/
@Bean
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
StringRedisTemplate template = new StringRedisTemplate();
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
template.setConnectionFactory(redisConnectionFactory);
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
// hash的key采用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
// value序列化方式采用jackson序列化方式
template.setValueSerializer(jackson2JsonRedisSerializer);
// hash的value序列化方式采用jackson序列化方式
template.setHashValueSerializer(jackson2JsonRedisSerializer);
return template;
}
}
三、測試
1、編寫redis工具類
雖然RedisTemplate與StringRedisTemplate模板有提供的主要數(shù)據(jù)訪問方法:
- opsForValue():操作只有簡單屬性的數(shù)據(jù)
- opsForList():操作含有List的數(shù)據(jù)
- opsForSet():操作含有set的數(shù)據(jù)
- opsForHash():操作含有hash的數(shù)據(jù)
- opsForZSet():操作含有有序set類型ZSet的數(shù)據(jù)
但是相關比較抽象,實現(xiàn)起來比較復雜,有必要進一步封裝,比如使用redisTmeplate中的簡單value的get操作:
Object result = null; ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue(); result = operations.get(key);
但是封裝之后,相對客戶端用戶來說比較明了
/**
* 讀取緩存
*
* @param key
* @return
*/
public Object get(final String key) {
Object result = null;
ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
result = operations.get(key);
return result;
}
完整的簡單工具類如下:
@Component
public class RedisUtils {
@Autowired
private RedisTemplate redisTemplate;
/**
* 批量刪除對應的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);
}
}
/**
* 刪除對應的value
*
* @param key
*/
public void remove(final String key) {
if (exists(key)) {
redisTemplate.delete(key);
}
}
/**
* 判斷緩存中是否有對應的value
*
* @param key
* @return
*/
public boolean exists(final String key) {
return redisTemplate.hasKey(key);
}
/**
* 讀取緩存
*
* @param key
* @return
*/
public Object get(final String key) {
Object result = null;
ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
result = operations.get(key);
return result;
}
/**
* 寫入緩存
*
* @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;
}
}
2、Person實體類
需要注意的是一定要實現(xiàn)序列化,并且有序列化版本ID
public class Person implements Serializable {
private final long serialVersionUID = 1L;
private String id;
private String name;
private int age;
private String gender;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
@Override
public String toString() {
return "Person{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", age=" + age +
", gender='" + gender + '\'' +
'}';
}
}
3、編寫測試類
Redis工具類Spring已經(jīng)做了管理(增加@Compent注解),使用很簡單,只需要注入RedisUtils即可
@RunWith(SpringRunner.class)
@SpringBootTest
public class RedisTest {
@Autowired
private RedisUtils redisUtils;
@Test
public void test(){
Person person = new Person();
person.setAge(23);
person.setId("001");
person.setName("Zhangsan");
redisUtils.set("person-001", person);
System.out.println(redisUtils.get("person-001"));
}
}
4、測試結果
在IDE控制臺中:
在登錄客戶端后查看value值

總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對腳本之家的支持。
相關文章
關于BeanUtils.copyProperties(source, target)的使用
這篇文章主要介紹了關于BeanUtils.copyProperties(source, target)的使用說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-06-06

