玩转SpringBoot2.x之缓存对象

前言

提到Redis 大部分的人首先想到的可能就是缓存,那么在 Java 项目中如何把对象缓存起来呢?这就是本文接下来要介绍的内容:缓存对象。本文通过SpringBoot 项目带你快速了解通过Jedis 把对象缓存到Redis中。

阅读本文需要你了解如何搭建 SpringBoot 项目即可,另外需要了解的是本文SpringBoot 版本是 2.1.0.RELEASE。关于SpringBoot 集成 Jedis 请参考:玩转 SpringBoot 2.x 之 快速集成 Jedis客户端(普通版)

接下来就让我们开始具体的代码案例介绍吧!

代码案例

演示通过将下面的 User 类创建的对象缓存到 Redis 中,具体有2种方式:序列化、Json。User 类具体代码如下:

public class User implements Serializable {

    private String name;
    private Integer age;

    public User(String name,Integer age){
        this.name = name;
        this.age = age;
    }
    //省略 getter and setter 方法
}

关于 过期时间处理和返回Jedis 线程操作到线程池操作封装到了 JedisCacheServiceSupport 中,具体代码如下:

public abstract class JedisCacheServiceSupport {
    public static final long EXPIRE_MILLISECONDS_DEFAULT_LONG = 3*60*60*1000;

    public Long getExpireTime(Long expireTime) {
        expireTime = (expireTime == null || expireTime.longValue() <= 0) ? EXPIRE_MILLISECONDS_DEFAULT_LONG : expireTime;
        return expireTime;
    }

    public void close(Jedis jedis){
        if(jedis != null){
            jedis.close();
        }
    }
}

序列化方式

序列化的方式通过现将对象转换成二进制的流(序列化)后保存到 Redis 中,然后通过key 获取到二进制,在把二进制流转换成对象(反序列化)。

保存对象的具体操作如下:

通过 ObjectOutputStream.writeObject(object) 将User 对象转换成byte 数组,然后通过 psetex(byte[] key, long milliseconds, byte[] value) 将 byte[] 数组存入Redis中。其中

  • byte[] key:需要将key 转换成byte数组。
  • long milliseconds:是对象在Redis 中存活的时间,以毫秒为单位。
  • byte[] value:对象转换成的btye 数组。

获取对象的具体操作如下:

通过 get(byte[] key) 获取 User 对象转换的byte 数组,然后通过 ObjectInputStream.readObject() 将数组转换成User对象。

通过序列化方式保存和获取对象具体代码如下:


@Service
public class JedisCacheService extends JedisCacheServiceSupport  {

    private static Logger logger = LoggerFactory.getLogger(JedisCacheService.class);



    @Autowired
    private JedisPool jedisPool;

    /**
     * 获取缓存中的对象
     * @param key
     * @return
     */
    public Object getObject(String key) {
        Jedis jedis = null;
        Object object = null;
        try {
            jedis = jedisPool.getResource();
            byte[] ObjectByteArray = jedis.get(key.getBytes());
            object = unserialize(ObjectByteArray);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            close(jedis);
        }
        return object;
    }

    /**
     *  将对象缓存到Redis中,设置默认过期时间
     * @param key
     * @param value
     */
    public void putObject(String key, Object value) {
        putObject(key,value,null);
    }
    /**
     *  将对象缓存到Redis中,自定义认过期时间
     * @param key
     * @param value
     */
    public void putObject(String key, Object value, Long expireTime) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            jedis.psetex(key.getBytes(),getExpireTime(expireTime),serialize(value));
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            close(jedis);
        }
    }


    /**
     * 序列化
     * @param object
     * @return
     */
    public static byte[] serialize(Object object) {
        ObjectOutputStream oos = null;
        ByteArrayOutputStream baos = null;
        try {
            baos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(baos);
            oos.writeObject(object);
            byte[] bytes = baos.toByteArray();
            return bytes;
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        } finally {
            IOUtil.closeStream(oos);
            IOUtil.closeStream(baos);
        }
        return null;
    }

    /**
     * 反序列化
     * @param bytes
     * @return
     */
    public static Object unserialize(byte[] bytes) {
        if (bytes == null) return null;

        ByteArrayInputStream bais = null;
        ObjectInputStream ois = null;
        try {
            bais = new ByteArrayInputStream(bytes);
            ois = new ObjectInputStream(bais);
            return ois.readObject();
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        } finally {
            IOUtil.closeStream(bais);
            IOUtil.closeStream(ois);
        }
        return null;
    }
}

关闭 输入流和输出流工具类具体代码如下:


public class IOUtil {
    public static void closeStream(InputStream inputStream) {
        if (inputStream != null) {
            try {
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }

    public static void closeStream(OutputStream outputStream) {
        if (outputStream != null) {
            try {
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }
}

序列化方式演示

测试 JedisCacheService putObject(将对象放入缓存中)、getObject(从缓存中获取对象),具体代码如下:

@RunWith(SpringRunner.class)
@SpringBootTest
public class JedisCacheServiceTest {
    private  Logger logger = LoggerFactory.getLogger(JedisCacheService.class);
    @Autowired
    private JedisCacheService jedisCacheService;

    @Test
    public void putObject() {
        User user = new User("zhuoqiammingyue",19);
        jedisCacheService.putObject("user01",user);
        logger.info("缓存用户成功!");
    }

    @Test
    public void getObject() {
        User user = (User)jedisCacheService.getObject("user01");
        logger.info("User name={},age={}",user.getName(),user.getAge());
    }
}

putObject 日志信息:

2020-02-26 22:08:50.320  INFO 26748 --- [           main] cn.lijunkui.cache.JedisCacheServiceTest  : Started JedisCacheServiceTest in 7.157 seconds (JVM running for 9.357)
2020-02-26 22:08:51.144  INFO 26748 --- [           main] cn.lijunkui.cache.JedisCacheService      : 缓存用户成功!

getObject 日志信息:

2020-02-26 22:09:57.492  INFO 9612 --- [           main] cn.lijunkui.cache.JedisCacheServiceTest  : Started JedisCacheServiceTest in 7.07 seconds (JVM running for 8.902)
2020-02-26 22:09:58.143  INFO 9612 --- [           main] cn.lijunkui.cache.JedisCacheService      : User name=zhuoqiammingyue,age=19

Json 方式

Json 的方式是将对象转换成可阅读的Json 串后保存到 Redis 中,然后通过key 获取到Json 串,在把Json 串成对象。对象转成成Json串是通过谷歌的Gson 完成的,所以需要引入Gson的依赖,具体依赖代码如下:

<dependency>
	<groupId>com.google.code.gson</groupId>
	<artifactId>gson</artifactId>
	<version>2.8.5</version>
</dependency>

Json 保存对象的具体操作如下:

通过 Gson.toJson(Object src) 将User 对象转换成 Json串,然后通过 psetex(String key, long milliseconds, String value) 将 Json串存入Redis中。

Json 获取对象的具体操作如下:

通过 get(String key) 获取 User 对象的Json串,然后通过 Gson.fromJson(String json, Class classOfT) 将Json串转换成User对象。

通过Json 方式保存和获取对象具体代码如下:

@Service
public class JedisJsonCacheService extends JedisCacheServiceSupport {

    private static Logger logger = LoggerFactory.getLogger(JedisJsonCacheService.class);

    @Autowired
    private JedisPool jedisPool;

    /**
     * 获取缓存中的对象
     * @param key
     * @param clazz
     * @return
     */
    public Object getObject(String key,Class clazz) {
        Jedis jedis = null;
        Object object = null;
        try {
            jedis = jedisPool.getResource();
            String objectJson = jedis.get(key);
             object = toObjce(objectJson,clazz);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            close(jedis);
        }
        return object;
    }
    
    /**
     * 将对象缓存到Redis中,设置默认过期时间
     * @param key
     * @param value
     */
    public void putObject(String key, Object value) {
        putObject(key, value,null);
    }

    /**
     * 将对象缓存到Redis中,自定义认过期时间
     * @param key
     * @param value
     * @param expireTime
     */
    public void putObject(String key, Object value, Long expireTime) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            jedis.psetex(key,getExpireTime(expireTime),toJson(value));
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            close(jedis);
        }
    }



    /**
     * 将对象转换成Json串
     * @param value
     * @return
     */
    private String toJson(Object value) {
        Gson gson = new Gson();
        return gson.toJson(value);
    }

    /**
     * 将Json串转换成对象
     * @param json
     * @param clazz
     * @return
     */
    private Object  toObjce(String json,Class clazz) {
        Gson gson = new Gson();
        return gson.fromJson(json,clazz);
    }
}

序列化方式演示

测试 JedisJsonCacheServiceTest putObject(将对象放入缓存中)、getObject(从缓存中获取对象),具体代码如下:

@RunWith(SpringRunner.class)
@SpringBootTest
public class JedisJsonCacheServiceTest {

    private Logger logger = LoggerFactory.getLogger(JedisJsonCacheServiceTest.class);
    @Autowired
    private JedisJsonCacheService jedisJsonCacheService;

    @Test
    public void putObject() {
        User user = new User("zhuoqiammingyue2",20);
        jedisJsonCacheService.putObject("user02",user);
        logger.info("缓存用户成功!");
    }

    @Test
    public void getObject() {
        User user = (User)jedisJsonCacheService.getObject("user02",User.class);
        logger.info("User name={},age={}",user.getName(),user.getAge());
    }
}

putObject 日志信息:

2020-02-27 07:57:16.184  INFO 3692 --- [           main] c.l.cache.JedisJsonCacheServiceTest      : Started JedisJsonCacheServiceTest in 7.92 seconds (JVM running for 10.786)
2020-02-27 07:57:16.852  INFO 3692 --- [           main] c.l.cache.JedisJsonCacheServiceTest      : 缓存用户成功!

getObject 日志信息:

2020-02-27 07:57:56.359  INFO 27624 --- [           main] c.l.cache.JedisJsonCacheServiceTest      : Started JedisJsonCacheServiceTest in 7.364 seconds (JVM running for 9.256)
2020-02-27 07:57:56.824  INFO 27624 --- [           main] c.l.cache.JedisJsonCacheServiceTest      : User name=zhuoqiammingyue2,age=20

小结

序列化和Json这2种方式,在实际开发中可以根据你的喜好自行选择。Json 方式使用的是Gson 当然你也可以使用 FastJson ,序列化采用了 Java 原生的序列化和反序列化,同时你也可以切换成效率更高的 Hessian 进行序列化和反序列化。

代码示例

我本地环境如下:

  • SpringBoot Version: 2.1.0.RELEASE
  • Apache Maven Version: 3.6.0
  • Java Version: 1.8.0_144
  • IDEA:IntellJ IDEA

操作过程如出现问题可以在我的GitHub 仓库 springbootexamples 中模块名为 spring-boot-2.x-redis-jedis-objectcache 项目中进行对比查看

GitHub:https://github.com/zhuoqianmingyue/springbootexamples

你可能感兴趣的:(【Redis】)