Spring Boot整合Redis

迷南。 2022-02-02 12:23 305阅读 0赞

一、Spring Boot对Redis的支持

Spring对Redis的支持是使用Spring Data Redis来实现的,一般使用Jedis或者lettuce(默认),Java客户端在 org.springframework.boot.autoconfigure.data.redis(Spring Boot 2.x) 中redis的自动配置 AutoConfigureDataRedis

                  1352849-20190508160938048-1486735555.png

RedisAutoConfiguration提供了RedisTemplate与StringRedisTemplate(只针对键值都是字符型的数据)模板,其中注解 @ConditionalOnMissingBean 是关键,表明该Bean如果在Spring中已经存在,则忽略,如果没有存在则在此处注册由Spring管理,也就是说我们可以“重写”该bean,实现自己的RedisTemplate与StringRedisTemplate,事实上,是要需要重写的,理由如下:

  • 没有实现我们所需要的序列化;
  • 泛型总是,大部分场景我们更需要

    @Bean

    1. @ConditionalOnMissingBean(
    2. name = {"redisTemplate"}
    3. )
    4. public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
    5. RedisTemplate<Object, Object> template = new RedisTemplate();
    6. template.setConnectionFactory(redisConnectionFactory);
    7. return template;
    8. }
    9. @Bean
    10. @ConditionalOnMissingBean
    11. public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
    12. StringRedisTemplate template = new StringRedisTemplate();
    13. template.setConnectionFactory(redisConnectionFactory);
    14. return template;
    15. }

二、实战

1、添加依赖

1)需要spring-boot-starter-cache依赖,管理缓存

  1. <!-- Spring Boot Cache -->
  2. <dependency>
  3. <groupId>org.springframework.boot</groupId>
  4. <artifactId>spring-boot-starter-cache</artifactId>
  5. </dependency>

2)需要spring-boot-starter-data-redis依赖(注:spring boot 2.x改为在data下),支持redis:主要以为Jedis客户端为主,排除默认的lettuce作为客户端的依赖

  1. <!-- Redis Cache -->
  2. <dependency>
  3. <groupId>org.springframework.boot</groupId>
  4. <artifactId>spring-boot-starter-data-redis</artifactId>
  5. <!-- 排除lettuce包,使用jedis代替-->
  6. <exclusions>
  7. <exclusion>
  8. <groupId>io.lettuce</groupId>
  9. <artifactId>lettuce-core</artifactId>
  10. </exclusion>
  11. </exclusions>
  12. </dependency>

3)需要jedis-client依赖(注:Redis Client 3版本以上会报错与spring-boot-starter-data-redis冲突,最好使用2.9.x),使用jedis作为客户端

  1. <!-- Redis Client 3版本以上会报错与spring-boot-starter-data-redis冲突 -->
  2. <dependency>
  3. <groupId>redis.clients</groupId>
  4. <artifactId>jedis</artifactId>
  5. <version>2.9.0</version>
  6. </dependency>

2、redis配置

创建RedisConfig配置类,增加@Configuration注解,同时开启缓存管理支持(添加注解@EnableCaching),继承CachingConfigurerSupport重写key生成策略

  1. @Configuration
  2. @EnableCaching
  3. public class RedisConfig extends CachingConfigurerSupport {
  4. /**
  5. * 生成key的策略:根据类名+方法名+所有参数的值生成唯一的一个key
  6. * @return
  7. */
  8. @Bean
  9. @Override
  10. public KeyGenerator keyGenerator() {
  11. return (Object target, Method method, Object... params) -> {
  12. StringBuilder sb = new StringBuilder();
  13. sb.append(target.getClass().getName());
  14. sb.append(method.getName());
  15. for (Object obj : params) {
  16. sb.append(obj.toString());
  17. }
  18. return sb.toString();
  19. };
  20. }
  21. }

之后使用的application.yml配置文件,其中这里已经选择jedis作为客户端。

  1. # redis 配置
  2. redis:
  3. port: 6379
  4. # Redis服务器连接密码(默认为空)
  5. password:
  6. host: xxx.xxx.xxx.xxx
  7. database: 0
  8. jedis:
  9. pool:
  10. #连接池最大连接数(使用负值表示没有限制)
  11. max-active: 300
  12. # 连接池中的最小空闲连接
  13. max-idle: 100
  14. # 连接池最大阻塞等待时间(使用负值表示没有限制)
  15. max-wait: 10000
  16. # 连接超时时间(毫秒)
  17. timeout: 5000

同时读取配置属性,注入JedisPoolConfig

  1.   /**
  2. * redis配置属性读取
  3. */
  4. @Value("${spring.redis.host}")
  5. private String host;
  6. @Value("${spring.redis.port}")
  7. private int port;
  8. @Value("${spring.redis.database}")
  9. private int database;
  10. @Value("${spring.redis.jedis.pool.max-idle}")
  11. private int maxIdle;
  12. @Value("${spring.redis.jedis.pool.max-wait}")
  13. private long maxWaitMillis;
  14. @Value("${spring.redis.jedis.pool.max-active}")
  15. private int maxActive;
  16. /**
  17. * JedisPoolConfig配置
  18. * @return
  19. */
  20. @Bean
  21. public JedisPoolConfig jedisPoolConfig() {
  22. log.info("初始化JedisPoolConfig");
  23. JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
  24. jedisPoolConfig.setMaxTotal(maxActive);
  25. jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);
  26. jedisPoolConfig.setMaxIdle(maxIdle);
  27. return jedisPoolConfig;
  28. }

3、实现序列化

针对RedisTemplate或StringRedisTemplate进行序列化,同时重写注册Bean

RedisTemplate默认使用JdkSerializationRedisSerializer,StringRedisTmeplate默认使用的是StringRedisSerializer。但都是不符合实际要求的

  1.  /**
  2. * 重新实现RedisTemplate:解决序列化问题
  3. * @param redisConnectionFactory
  4. * @return
  5. */
  6. @Bean
  7. @SuppressWarnings({"rawtype", "unchecked"})
  8. public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
  9. RedisTemplate<String, Object> template = new RedisTemplate();
  10. template.setConnectionFactory(redisConnectionFactory);
  11. Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
  12. ObjectMapper om = new ObjectMapper();
  13. // 设置任何字段可见
  14. om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
  15. // 设置不是final的属性可以转换
  16. om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
  17. log.info("objectMapper: {}", om);
  18. jackson2JsonRedisSerializer.setObjectMapper(om);
  19. StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
  20. // key采用String的序列化方式
  21. template.setKeySerializer(stringRedisSerializer);
  22. // hash的key采用String的序列化方式
  23. template.setHashKeySerializer(stringRedisSerializer);
  24. // value序列化方式采用jackson序列化方式
  25. template.setValueSerializer(jackson2JsonRedisSerializer);
  26. // hash的value序列化方式采用jackson序列化方式
  27. template.setHashValueSerializer(jackson2JsonRedisSerializer);
  28. template.afterPropertiesSet();
  29. template.setEnableTransactionSupport(true);
  30. return template;
  31. }
  32. /**
  33. * 重新实现StringRedisTmeplate:键值都是String的的数据
  34. * @param redisConnectionFactory
  35. * @return
  36. */
  37. @Bean
  38. public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
  39. StringRedisTemplate template = new StringRedisTemplate();
  40. Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
  41. template.setConnectionFactory(redisConnectionFactory);
  42. StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
  43. // key采用String的序列化方式
  44. template.setKeySerializer(stringRedisSerializer);
  45. // hash的key采用String的序列化方式
  46. template.setHashKeySerializer(stringRedisSerializer);
  47. // value序列化方式采用jackson序列化方式
  48. template.setValueSerializer(jackson2JsonRedisSerializer);
  49. // hash的value序列化方式采用jackson序列化方式
  50. template.setHashValueSerializer(jackson2JsonRedisSerializer);
  51. return template;
  52. }

4、创建Redis连接工厂,同时注册Bean

 注意Spring Boot 1.x与Spring Boot 2.x的区别,已在代码中注释表明,Spring Boot 1.x使用的是JedisConnectionFactory 。而Spring Boot 2.x使用的是RedisStandaloneConfiguration ,之后传入JedisConnectionFactory返回Bean

  1.   /**
  2. * 注入RedisConnectionFactory
  3. * @return
  4. */
  5. @Bean
  6. public RedisConnectionFactory redisConnectionFactory(JedisPoolConfig jedisPoolConfig) {
  7. log.info("初始化JedisConnectionFactory");
  8. /* 在Spring Boot 1.x中已经过时,采用RedisStandaloneConfiguration配置
  9. JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(jedisPoolConfig);
  10. jedisConnectionFactory.setHostName(host);
  11. jedisConnectionFactory.setDatabase(database);*/
  12. // JedisConnectionFactory配置hsot、database、password等参数
  13. RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
  14. redisStandaloneConfiguration.setHostName(host);
  15. redisStandaloneConfiguration.setPort(port);
  16. redisStandaloneConfiguration.setDatabase(database);
  17. // JedisConnectionFactory配置jedisPoolConfig
  18. JedisClientConfiguration.JedisPoolingClientConfigurationBuilder jedisPoolConfigBuilder =
  19. (JedisClientConfiguration.JedisPoolingClientConfigurationBuilder)JedisClientConfiguration.builder();
  20. jedisPoolConfigBuilder.poolConfig(jedisPoolConfig);
  21. return new JedisConnectionFactory(redisStandaloneConfiguration);
  22. }

5、完整的RedisConfig配置类

  1. /**
  2. *
  3. * @author jian
  4. * @date 2019/4/14
  5. * @description
  6. * 1) RedisTemplate(或StringRedisTemplate)虽然已经自动配置,但是不灵活(第一没有序列化,第二泛型为<Object, Object>不是我们想要的类型)
  7. * 所以自己实现RedisTemplate或StringRedisTemplate)
  8. * 2) 采用RedisCacheManager作为缓存管理器
  9. *
  10. */
  11. @Configuration
  12. @EnableCaching
  13. public class RedisConfig extends CachingConfigurerSupport {
  14. private static final Logger log = LoggerFactory.getLogger(RedisConfig.class);
  15. /**
  16. * redis配置属性读取
  17. */
  18. @Value("${spring.redis.host}")
  19. private String host;
  20. @Value("${spring.redis.port}")
  21. private int port;
  22. @Value("${spring.redis.database}")
  23. private int database;
  24. @Value("${spring.redis.jedis.pool.max-idle}")
  25. private int maxIdle;
  26. @Value("${spring.redis.jedis.pool.max-wait}")
  27. private long maxWaitMillis;
  28. @Value("${spring.redis.jedis.pool.max-active}")
  29. private int maxActive;
  30. /**
  31. * JedisPoolConfig配置
  32. * @return
  33. */
  34. @Bean
  35. public JedisPoolConfig jedisPoolConfig() {
  36. log.info("初始化JedisPoolConfig");
  37. JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
  38. jedisPoolConfig.setMaxTotal(maxActive);
  39. jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);
  40. jedisPoolConfig.setMaxIdle(maxIdle);
  41. return jedisPoolConfig;
  42. }
  43. /**
  44. * 注入RedisConnectionFactory
  45. * @return
  46. */
  47. @Bean
  48. public RedisConnectionFactory redisConnectionFactory(JedisPoolConfig jedisPoolConfig) {
  49. log.info("初始化JedisConnectionFactory");
  50. /* 在Spring Boot 1.x中已经过时,采用RedisStandaloneConfiguration配置
  51. JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(jedisPoolConfig);
  52. jedisConnectionFactory.setHostName(host);
  53. jedisConnectionFactory.setDatabase(database);*/
  54. // JedisConnectionFactory配置hsot、database、password等参数
  55. RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
  56. redisStandaloneConfiguration.setHostName(host);
  57. redisStandaloneConfiguration.setPort(port);
  58. redisStandaloneConfiguration.setDatabase(database);
  59. // JedisConnectionFactory配置jedisPoolConfig
  60. JedisClientConfiguration.JedisPoolingClientConfigurationBuilder jedisPoolConfigBuilder =
  61. (JedisClientConfiguration.JedisPoolingClientConfigurationBuilder)JedisClientConfiguration.builder();
  62. jedisPoolConfigBuilder.poolConfig(jedisPoolConfig);
  63. return new JedisConnectionFactory(redisStandaloneConfiguration);
  64. }
  65. /**
  66. * 采用RedisCacheManager作为缓存管理器
  67. * @param connectionFactory
  68. */
  69. @Bean
  70. public CacheManager cacheManager(RedisConnectionFactory connectionFactory) {
  71. RedisCacheManager redisCacheManager = RedisCacheManager.create(connectionFactory);
  72. return redisCacheManager;
  73. }
  74. /**
  75. * 生成key的策略:根据类名+方法名+所有参数的值生成唯一的一个key
  76. * @return
  77. */
  78. @Bean
  79. @Override
  80. public KeyGenerator keyGenerator() {
  81. return (Object target, Method method, Object... params) -> {
  82. StringBuilder sb = new StringBuilder();
  83. sb.append(target.getClass().getName());
  84. sb.append(method.getName());
  85. for (Object obj : params) {
  86. sb.append(obj.toString());
  87. }
  88. return sb.toString();
  89. };
  90. }
  91. /**
  92. * 重新实现RedisTemplate:解决序列化问题
  93. * @param redisConnectionFactory
  94. * @return
  95. */
  96. @Bean
  97. @SuppressWarnings({"rawtype", "unchecked"})
  98. public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
  99. RedisTemplate<String, Object> template = new RedisTemplate();
  100. template.setConnectionFactory(redisConnectionFactory);
  101. Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
  102. ObjectMapper om = new ObjectMapper();
  103. // 设置任何字段可见
  104. om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
  105. // 设置不是final的属性可以转换
  106. om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
  107. log.info("objectMapper: {}", om);
  108. jackson2JsonRedisSerializer.setObjectMapper(om);
  109. StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
  110. // key采用String的序列化方式
  111. template.setKeySerializer(stringRedisSerializer);
  112. // hash的key采用String的序列化方式
  113. template.setHashKeySerializer(stringRedisSerializer);
  114. // value序列化方式采用jackson序列化方式
  115. template.setValueSerializer(jackson2JsonRedisSerializer);
  116. // hash的value序列化方式采用jackson序列化方式
  117. template.setHashValueSerializer(jackson2JsonRedisSerializer);
  118. template.afterPropertiesSet();
  119. template.setEnableTransactionSupport(true);
  120. return template;
  121. }
  122. /**
  123. * 重新实现StringRedisTmeplate:键值都是String的的数据
  124. * @param redisConnectionFactory
  125. * @return
  126. */
  127. @Bean
  128. public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
  129. StringRedisTemplate template = new StringRedisTemplate();
  130. Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
  131. template.setConnectionFactory(redisConnectionFactory);
  132. StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
  133. // key采用String的序列化方式
  134. template.setKeySerializer(stringRedisSerializer);
  135. // hash的key采用String的序列化方式
  136. template.setHashKeySerializer(stringRedisSerializer);
  137. // value序列化方式采用jackson序列化方式
  138. template.setValueSerializer(jackson2JsonRedisSerializer);
  139. // hash的value序列化方式采用jackson序列化方式
  140. template.setHashValueSerializer(jackson2JsonRedisSerializer);
  141. return template;
  142. }
  143. }

三、测试

1、编写redis工具类

虽然RedisTemplate与StringRedisTemplate模板有提供的主要数据访问方法:

  • opsForValue():操作只有简单属性的数据
  • opsForList():操作含有List的数据
  • opsForSet():操作含有set的数据
  • opsForHash():操作含有hash的数据
  • opsForZSet():操作含有有序set类型ZSet的数据

但是相关比较抽象,实现起来比较复杂,有必要进一步封装,比如使用redisTmeplate中的简单value的get操作:

  1. Object result = null;
  2. ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
  3. result = operations.get(key);

但是封装之后,相对客户端用户来说比较明了

  1.   /**
  2. * 读取缓存
  3. *
  4. * @param key
  5. * @return
  6. */
  7. public Object get(final String key) {
  8. Object result = null;
  9. ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
  10. result = operations.get(key);
  11. return result;
  12. }

完整的简单工具类如下:

  1. @Component
  2. public class RedisUtils {
  3. @Autowired
  4. private RedisTemplate redisTemplate;
  5. /**
  6. * 批量删除对应的value
  7. *
  8. * @param keys
  9. */
  10. public void remove(final String... keys) {
  11. for (String key : keys) {
  12. remove(key);
  13. }
  14. }
  15. /**
  16. * 批量删除key
  17. *
  18. * @param pattern
  19. */
  20. public void removePattern(final String pattern) {
  21. Set<Serializable> keys = redisTemplate.keys(pattern);
  22. if (keys.size() > 0) {
  23. redisTemplate.delete(keys);
  24. }
  25. }
  26. /**
  27. * 删除对应的value
  28. *
  29. * @param key
  30. */
  31. public void remove(final String key) {
  32. if (exists(key)) {
  33. redisTemplate.delete(key);
  34. }
  35. }
  36. /**
  37. * 判断缓存中是否有对应的value
  38. *
  39. * @param key
  40. * @return
  41. */
  42. public boolean exists(final String key) {
  43. return redisTemplate.hasKey(key);
  44. }
  45. /**
  46. * 读取缓存
  47. *
  48. * @param key
  49. * @return
  50. */
  51. public Object get(final String key) {
  52. Object result = null;
  53. ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
  54. result = operations.get(key);
  55. return result;
  56. }
  57. /**
  58. * 写入缓存
  59. *
  60. * @param key
  61. * @param value
  62. * @return
  63. */
  64. public boolean set(final String key, Object value) {
  65. boolean result = false;
  66. try {
  67. ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
  68. operations.set(key, value);
  69. result = true;
  70. } catch (Exception e) {
  71. e.printStackTrace();
  72. }
  73. return result;
  74. }
  75. /**
  76. * 写入缓存
  77. *
  78. * @param key
  79. * @param value
  80. * @return
  81. */
  82. public boolean set(final String key, Object value, Long expireTime) {
  83. boolean result = false;
  84. try {
  85. ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
  86. operations.set(key, value);
  87. redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
  88. result = true;
  89. } catch (Exception e) {
  90. e.printStackTrace();
  91. }
  92. return result;
  93. }
  94. }

2、Person实体类

需要注意的是一定要实现序列化,并且有序列化版本ID

  1. public class Person implements Serializable {
  2. private final long serialVersionUID = 1L;
  3. private String id;
  4. private String name;
  5. private int age;
  6. private String gender;
  7. public String getId() {
  8. return id;
  9. }
  10. public void setId(String id) {
  11. this.id = id;
  12. }
  13. public String getName() {
  14. return name;
  15. }
  16. public void setName(String name) {
  17. this.name = name;
  18. }
  19. public int getAge() {
  20. return age;
  21. }
  22. public void setAge(int age) {
  23. this.age = age;
  24. }
  25. public String getGender() {
  26. return gender;
  27. }
  28. public void setGender(String gender) {
  29. this.gender = gender;
  30. }
  31. @Override
  32. public String toString() {
  33. return "Person{" +
  34. "id='" + id + '\'' +
  35. ", name='" + name + '\'' +
  36. ", age=" + age +
  37. ", gender='" + gender + '\'' +
  38. '}';
  39. }
  40. }

3、编写测试类

Redis工具类Spring已经做了管理(增加@Compent注解),使用很简单,只需要注入RedisUtils即可

  1. @RunWith(SpringRunner.class)
  2. @SpringBootTest
  3. public class RedisTest {
  4. @Autowired
  5. private RedisUtils redisUtils;
  6. @Test
  7. public void test(){
  8. Person person = new Person();
  9. person.setAge(23);
  10. person.setId("001");
  11. person.setName("Zhangsan");
  12. redisUtils.set("person-001", person);
  13. System.out.println(redisUtils.get("person-001"));
  14. }
  15. }

4、测试结果

在IDE控制台中:

1352849-20190508170544288-456874393.png

在登录客户端后查看value值

1352849-20190508170714657-1416109984.png

发表评论

表情:
评论列表 (有 0 条评论,305人围观)

还没有评论,来说两句吧...

相关阅读