玩转 SpringBoot2.x 之缓存对象

用户头像
zhuoqianmingyue
关注
发布于: 2020 年 05 月 25 日

前言

提到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<T> 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



发布于: 2020 年 05 月 25 日 阅读数: 38
用户头像

zhuoqianmingyue

关注

还未添加个人签名 2018.11.05 加入

还未添加个人简介

评论

发布
暂无评论
玩转SpringBoot2.x之缓存对象