---主要探讨java,hadoop,redis等的序列化问题
当两个进程在进行远程通信时,彼此可以发送各种类型的数据。无论是何种类型的数据,都会以二进制序列的形式在网络上传送。发送方需要把这个对象转换为字节序列,才能在网络上传送;接收方则需要把字节序列再恢复为对象。
把对象转换为字节序列的过程称为对象的序列化序列化序列化序列化。
把字节序列恢复为对象的过程称为对象的反序列化反序列化反序列化反序列化。
对象的序列化主要有两种用途对象的序列化主要有两种用途对象的序列化主要有两种用途对象的序列化主要有两种用途:
1、把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中
2、在网络上传送对象的字节序。
java,hadoop,redis的对象类型值都要求序列化。一方面为了能存储到硬盘,另外hadoop的序列化还用于RPC通信。
java的序列化 需要序列化的类要实现Seriallizable接口,给一个序列号。然后序列化对象时有自己的一套机制。每个对象写入时都要写入其类名。实例之间的引用使用句柄,不适合随即访问,而且会对排序记录造成破坏。其实现较简单,需要序列化的类实现serializable接口,然后自定义工具类去处理。
hadoop的writable可以避免java序列化的问题,做到精简,快速,可扩展,互操作,支持随机存取,排序。需序列化的类实现writable接口,并实现readfields和write方法。如果类比较简单,像这样:
@Override
public void write(DataOutput out) throws IOException {
out.writeInt(uid);
out.writeChar(address);
}
@Override
public void readFields(DataInput in) throws IOException {
uid = in.readInt();
address = in.readChar();
}
复杂一点的可能实现的代码要多点,特别是类属性包含了集合<对象>,string等,这是write方法可以先写入大小,再去写对象,读时根据写入格式读。这样我们可以定制序列化的内容,只序列化我们感兴趣的数据。
redis保存的数据会在内存和硬盘上存储,所以也需要序列化。使用jedis和spring-data-redis时要注意序列化带来的问题。可以使用redisTemplate 去做,支持的序列化类型比较多,类似jedis客户端连接的功能已经内置到里面去了,用户只要关心业务逻辑,例如:
@Autowired
private RedisTemplate<String, String> redisTemplate;
public void save(final User user) {
redisTemplate.execute(new RedisCallback<Object>() {
@Override
public Object doInRedis(RedisConnection connection)
throws DataAccessException {
connection.set(
redisTemplate.getStringSerializer().serialize(
user.getUid()),
redisTemplate.getStringSerializer().serialize(
user.getAddress()));
return null;
}
});
}
使用时:
@Test
public void testSave(){
user = new User();
user.setAddress(address1);
user.setUid(uid);
userDao.save(user);
}
不过我还是喜欢用sharedJedis直接去操作:
@Override
public ResultSet getResultSetCache(String key) {
try {
log.info("get object from redisCache :"+key);
ShardedJedis jedis = pool.getResource();
ResultSet value = SerializableUtils.deSerialize(jedis.get(key.getBytes()), ResultSet.class);
pool.returnResource(jedis);
return value;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
public boolean setResultSetCache(String key, ResultSet value) {
try {
log.info("add object to redisCache :"+key);
ShardedJedis jedis = pool.getResource();
jedis.set(key.getBytes(),SerializableUtils.serialize(value));
pool.returnResource(jedis);
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
序列化工具类:
public class SerializableUtils {
public static<T extends Writable> byte[] serialize(Object value) throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream oos = new DataOutputStream(bos);
if (value instanceof Writable) {
((T) value).write(oos);
} else {
throw new IOException("not instanceof Writable!");
}
return bos.toByteArray();
}
public static <T extends Writable> T deSerialize(byte[] byteCode,Class<T> classType) throws IOException{
ByteArrayInputStream bis = new ByteArrayInputStream(byteCode);
T object = null;
try {
DataInputStream dis = new DataInputStream(bis);
object = (T)classType.newInstance();
object.readFields(dis);
return object;
} catch (IOException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
}