当前位置: 移动技术网 > IT编程>开发语言>Java > Spring Boot整合Redis

Spring Boot整合Redis

2019年05月09日  | 移动技术网IT编程  | 我要评论

一、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值

 

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网