Spring Boot整合Redis - JJian - 博客园 --- 亲测可用 ---- springboot 2.x

一、Spring Boot对Redis的支持

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

                  

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

  • 没有实现我们所需要的序列化;
  • 泛型总是<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;
}

复制代码; "复制代码")

二、实战

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配置

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

复制代码; "复制代码")

@Configuration
@EnableCaching public class RedisConfig extends CachingConfigurerSupport { /** * 生成key的策略:根据类名+方法名+所有参数的值生成唯一的一个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配置文件,其中这里已经选择jedis作为客户端。

复制代码; "复制代码")

# redis 配置
redis:

  port: 6379
  # Redis服务器连接密码(默认为空)
  password:
  host: xxx.xxx.xxx.xxx
  database: 0
  jedis:
    pool:
      #连接池最大连接数(使用负值表示没有限制)
      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、实现序列化

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

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

复制代码; "复制代码")

 /** * 重新实现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;
} /** \* 重新实现StringRedisTmeplate:键值都是String的的数据
 \* @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;

}

复制代码; "复制代码")

View Code

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

 注意Spring Boot 1.x与Spring Boot 2.x的区别,已在代码中注释表明,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中已经过时,采用RedisStandaloneConfiguration配置
    JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(jedisPoolConfig);
    jedisConnectionFactory.setHostName(host);
    jedisConnectionFactory.setDatabase(database);*/

    // JedisConnectionFactory配置hsot、database、password等参数
    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)虽然已经自动配置,但是不灵活(第一没有序列化,第二泛型为<Object, Object>不是我们想要的类型)
* 所以自己实现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中已经过时,采用RedisStandaloneConfiguration配置
    JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(jedisPoolConfig);
    jedisConnectionFactory.setHostName(host);
    jedisConnectionFactory.setDatabase(database);*/

    // JedisConnectionFactory配置hsot、database、password等参数
    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的策略:根据类名+方法名+所有参数的值生成唯一的一个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();
    };
} /** \* 重新实现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;
} /** \* 重新实现StringRedisTmeplate:键值都是String的的数据
 \* @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;

}

}

复制代码; "复制代码")

View Code

三、测试

1、编写redis工具类

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

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

但是相关比较抽象,实现起来比较复杂,有必要进一步封装,比如使用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;
}

}

复制代码; "复制代码")

View Code

2、Person实体类

需要注意的是一定要实现序列化,并且有序列化版本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 + '\\'' +
            '}';
}

}

复制代码; "复制代码")

View Code

3、编写测试类

Redis工具类Spring已经做了管理(增加@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值


Original url: Access
Created at: 2020-04-16 17:20:24
Category: default
Tags: none

请先后发表评论
  • 最新评论
  • 总共0条评论