业务场景中经常遇到使用Redis作为缓存,而将对象写入Redis更是常见的。下面来看下,对象写入Redis的俩种方式(我之前就知道除了JDK,还有其它的诸如Jackson提供序列化功能,但是JDK之外的其它第三方在方序列化的时候提供目标对象class,不过今天我发现Spring-data-redis自带的这个GenericJackson2JsonRedisSerializer解决了我的烦恼)。
List-1 连接池和ConnectionFactory配置
<bean id="pool" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxTotal" value="30"/>
<property name="maxIdle" value="10"/>
<property name="minEvictableIdleTimeMillis" value="100000"/>
<property name="numTestsPerEvictionRun" value="1024"/>
</bean>
<bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<!--<constructor-arg name="sentinelConfig" ref="redisSentinelConfiguration"/>-->
<constructor-arg name="poolConfig" ref="pool"/>
<property name="hostName" value="localhost"/>
<property name="port" value="6379"/>
<property name="database" value="7"/>
</bean>
List-2 使用JDK的序列化方式
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="jedisConnectionFactory"/>
<property name="keySerializer">
<bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/>
</property>
<property name="valueSerializer">
<bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/>
</property>
</bean>
如List-2所示,我们要将keySerializer和valueSerializer的值设置为JdkSerializationRedisSerializer。
List-2 使用Jackson作为序列化
<bean id="jacksonRedisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="jedisConnectionFactory"/>
<property name="keySerializer">
<bean class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer"/>
</property>
<property name="valueSerializer">
<bean class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer"/>
</property>
</bean>
我们都知道Jackson反序列化的时候,都需要传入目标对象class,这里我们并不需要指定目标class,那么问题来了,它是怎么做到在使用者不提供目标class的情况下,方序列化的呢?
先来定义实体类,如下List-3和List-4
List-3 Department.java
/**
* @author dmj1161859184@126.com 2018-09-18 01:21
* @version 1.0
* @since 1.0
*/
@Data
public class Department {
private String name;
private List<OfficeStaff> officeStaffs;
private List<String> strings = Collections.emptyList();
private String other;
public Department(String name, List<OfficeStaff> officeStaffs, List<String> strings) {
this.name = name;
this.officeStaffs = officeStaffs;
this.strings = strings;
}
}
List-4 OfficeStaff.java
/**
* @author dmj1161859184@126.com 2018-09-18 01:22
* @version 1.0
* @since 1.0
*/
@Data
@AllArgsConstructor
public class OfficeStaff {
private String name;
private Integer age;
}
如下List-5所示,Jackson序列化方式将Department写入Redis后,对象被转换为json字符串,同时,还有额外的"@class"字段表示对象类型。看到这个"@class",应该明白了,这个在方序列化的时候用到,由于在序列化写入Redis的时候就将对象类型写入到Redis了,所以方序列化的时候不需要提供目标对象class。
List-5 Department对象在Redis中存储的是json
127.0.0.1:6379[7]> get "\"System\""
"{\"@class\":\"com.mjduan.project.objectRedisTemplate.model.Department\",\"name\":\"System\",\"officeStaffs\":[\"java.util.ArrayList\",[{\"@class\":\"com.mjduan.project.objectRedisTemplate.model.OfficeStaff\",\"name\":\"Jack\"}]],\"other\":\"other\"}"
127.0.0.1:6379[7]>
注:除了引入Spring-data-redis和Jedis,还需要引入jackson的依赖,我使用的版本如下List-6:
List-6
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.8.8</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.8</version>
</dependency>
在将对象序列化到Redis中时,该选择JDK方式还是Jackson方式,我会选择使用Jackson的方式,why,因为JDK序列化方式很大的一个限制就是要求对象必须实现Serializable,而且是递归的(比如类A有个属性类B,那么类A和类B都要实现Serializable),特别是对遗留系统,很多存入缓存的对象很有可能没有实现Serializable,如果使用JDK序列化方式的话,需要确认所有的对象都实现了Serializable,这个很耗时,且不一定能完全覆盖。当然了,选择Jackson序列化方式,也有未知的问题,只是目前还没遇到。
(adsbygoogle = window.adsbygoogle || []).push({});