Spring Boot整合Redis

一、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;
    }

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;
    }

}

三、测试

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;
    }
}

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 + ‘\‘‘ +
                ‘}‘;
    }
}

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值

原文地址:https://www.cnblogs.com/jian0110/p/10833056.html

时间: 2024-10-05 20:00:00

Spring Boot整合Redis的相关文章

Spring Boot 整合Redis 实现缓存

本文提纲 一.缓存的应用场景 二.更新缓存的策略 三.运行 springboot-mybatis-redis 工程案例 四.springboot-mybatis-redis 工程代码配置详解 运行环境: Mac OS 10.12.x JDK 8 + Redis 3.2.8 Spring Boot 1.5.1.RELEASE 一.缓存的应用场景 什么是缓存? 在互联网场景下,尤其 2C 端大流量场景下,需要将一些经常展现和不会频繁变更的数据,存放在存取速率更快的地方.缓存就是一个存储器,在技术选型

spring boot 整合 redis

自己开发环境需要安装 redis 服务,百度一下很多,下面主要说明Springboot 集成 redis 讲解 我的版本 java8 + redis3.0 + springboot 1.5.9. Spring redis 集成了 jedis redis 中存储的是 bytes 1 spring boot已经支持集成 redis,在 mvn 中只需添加依赖即可.pom 配置片段如下 <parent> <groupId>org.springframework.boot</grou

spring boot整合redis多实例

最近项目中遇到需要连接两个redis实例的情况,于是就在spring boot原先的基础上修改了一点. 1. 定义配置文件的bean,继承自RedisProperties 下面是配置文件的内容 redis: config: multiple: - name: develop database: 0 lettuce: pool: max-idle: 10 max-active: 1000 max-wait: 1000ms min-idle: 5 timeout: 100000ms cluster:

Spring boot 整合redis单机版

   一.安装redis 这个不多说,网上有各种系统安装redis的操作, redis安装 二.创建sprigboot项目 这个也不多说,不会的前面有相关教程. 三.添加maven坐标 四.编写springboot配置文件 五.可以操作redis了 我把缓存存在redis 相关代码如下: 5.1目录结构 5.2 模拟数据 5.3缓存 5.4开启缓存 5.5测试接口 六.当第一次访问的时候打印 第二次直接从redis中获得数据 如果有什么问题,可以一起探讨欢迎加我qq1058179540 原文地址

Spring Boot 整合 Lettuce Redis

SpringBoot?是为了简化?Spring?应用的创建.运行.调试.部署等一系列问题而诞生的产物,自动装配的特性让我们可以更好的关注业务本身而不是外部的XML配置,我们只需遵循规范,引入相关的依赖就可以轻易的搭建出一个 WEB 工程 Spring Boot?除了支持常见的ORM框架外,更是对常用的中间件提供了非常好封装,随着Spring Boot2.x的到来,支持的组件越来越丰富,也越来越成熟,其中对Redis的支持不仅仅是丰富了它的API,更是替换掉底层Jedis的依赖,取而代之换成了Le

Spring Boot使用redis实现数据缓存

基于Spring Boot 1.5.2.RELEASE版本,一方面验证与Redis的集成方法,另外了解使用方法. 集成方法 配置依赖 修改pom.xml,增加如下内容. <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> 配置Redis

Spring boot、Redis、ActiveMQ、Nginx、Mycat、Netty、Jvm大型分布式项目实战视频教程

15套java架构师.集群.高可用.高可扩展.高性能.高并发.性能优化.Spring boot.Redis.ActiveMQ.Nginx.Mycat.Netty.Jvm大型分布式项目实战视频教程 视频课程内容包含: 高级Java架构师包含:Spring boot.Spring  cloud.Dubbo.Redis.ActiveMQ.Nginx.Mycat.Spring.MongoDB.ZeroMQ.Git.Nosql.Jvm.Mecached.Netty.Nio.Mina.性能调优.高并发.to

spring boot 整合 quartz 集群环境 实现 动态定时任务配置【原】

最近做了一个spring boot 整合 quartz  实现 动态定时任务配置,在集群环境下运行的 任务.能够对定时任务,动态的进行增删改查,界面效果图如下: 1. 在项目中引入jar 2. 将需要的表导入数据库 官网上有不同数据库的脚本,找到对应的,导入即可 3. java 代码 将quartz 的相关配置文件,配置为暴露bean,方便后期引用. 有一处关键的地方,就是注入spring 上下文,也可以算是一个坑.如果,不注入spring 上下文,那么新添加的定时任务job,是新new 的一个

spring boot,gradle,redis

今天做spring boot/gradle/redis相关的项目,遇到若干问题,记录如下: spring boot  org.springframework.session.data.redis.RedisFlushMode 这个报错是与redis服务器连接的问题,查看一下在application.properties里写的redis服务器IP是不是错了,改正即可;或者redis服务器启用了protected-mode,运行Redis时使用命令: nohup redis-server --pro