(记录)Jedis存放对象和读取对象--Java序列化与反序列化
⼀、理论分析
在学习Redis中的Jedis这⼀部分的时候,要使⽤到Protostuff(Protobuf的Java客户端)这⼀序列化⼯具。⼀开始看到序列化这些字眼的时候,感觉到⼀头雾⽔。于是,参考了⽹上的很多资料,理解了Java序列化与反序列化(参考blog.csdn/wangloveall/article/details/7992448/),Protobuf的作⽤以及在Java中的使⽤⽅法。
1.Java序列化与反序列化是什么:
Java序列化是指把Java对象转换为字节序列的过程;⽽Java反序列化是指把字节序列恢复为Java对象的过程。
2.为什么需要Java序列化与反序列化
序列化的两种⾮常重要的应⽤:
使⽤序列化将对象集合保存到磁盘⽂件中,并按照它们被存储的样⼦获取它们。
通过⽹络将对象集合传送到另⼀台计算机上。
3.为什么只能⽤序列化和反序列化
在磁盘⽂件中,不能去保存和恢复对象的内存地址是因为对象被重载时,它可能占据的是与原来完全不同的内存地址。
在⽹络传输中,不同的处理器之间通信时,对象占据的内存地址也是完全不同。
4.序列化和反序列化的好处
序列化就是每个对象都是⽤⼀个序列号保存的,这就是这种机制被称为序列化的原因。
5.实现Java对象序列化与反序列化的⽅法
JDK库中的序列化API实现⼆进制序列化
XML
JSON
Protostaff
6.JDK库中序列化与反序列化:
(1)对象序列化包括如下步骤:
创建⼀个对象输出流,它可以包装⼀个其他类的⽬标输出流,如⽂件输出流;
通过对象输出流的writeObject()⽅法写对象。
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("empoyee.dat"));
Employee harry = new Employee("Harry Hacker", 5000, 1989, 10, 1);
Maneger boss = new Manager("Carl Cracker", 7000, 1984, 12, 15);
oos.writeObject(harry);
oos.writeObject(boss);
(2)对象反序列化包括如下步骤:
创建⼀个对象输⼊流,它可以包装⼀个其他类型的源输⼊流,如⽂件输⼊流;
通过对象输⼊流的readObject()⽅法以这些对象被写出的顺序读取对象并获得它们。
ObjectInputStream ois = new ObjectInputStream (new FileInputStream("empoyee.dat"));
Employee e1 = (adObject();
Maneger e2 = (adObject();
(3)对于那么需要序列化与反序列化的对象,对应的类必须要实现JDK库的相关API,有以下三种⽅法:
若Club类仅仅实现了Serializable接⼝,则可以按照以下⽅式进⾏序列化和反序列化
ObjectOutputStream采⽤默认的序列化⽅式,对Club对象的⾮transient的实例变量进⾏序列化。
ObjcetInputStream采⽤默认的反序列化⽅式,对对Club对象的⾮transient的实例变量进⾏反序列化。
若Club类仅仅实现了Serializable接⼝,并且还定义了readObject(ObjectInputStream in)和writeObject(ObjectOutputSteam out),则采⽤以下⽅式进⾏序列化与反序列化。
ObjectOutputStream调⽤Student对象的writeObject(ObjectOutputStream out)的⽅法进⾏序列化。
ObjectInputStream会调⽤Student对象的readObject(ObjectInputStream in)的⽅法进⾏反序列化。
若Club类实现了Externalnalizable接⼝,且Club类必须实现readExternal(ObjectInput in)和writeExternal(ObjectOutput out)⽅法,则按照以下⽅式进⾏序列化与反序列化。
ObjectOutputStream调⽤Student对象的writeExternal(ObjectOutput out))的⽅法进⾏序列化。
ObjectInputStream会调⽤Student对象的readExternal(ObjectInput in)的⽅法进⾏反序列化。
⼆、⽰例程序分析
1.测试环境:
虚拟机ubuntu 16.04
Jedis版本:Jedis-2.9.0.jar
主机ping 192.168.131.130可以ping通。
2.主机上运⾏eclipse程序,证明可以连接到redis服务器
package bigjun.iplab.jedisConnectTest;
import redis.clients.jedis.Jedis;
public class JedisConnectTest {
public static void main(String[] args) {
@SuppressWarnings("resource")
Jedis jedis = new Jedis("192.168.131.130");
jedis.set("JedisConnectTest", "pass");
String getResult = ("JedisConnectTest");
System.out.println(getResult);
}
}
控制台输出pass,同时查看ubuntu系统上redis中成功存⼊redis数据。
3.Jedis将对象序列化为⼆进制的API:
public String set(final String key, String value)
public String set(final byte[] key, final byte[] value)
public byte[] get(final byte[] key)
public String get(final String key)
有了这些API的⽀持,就可以将Java对象序列化为⼆进制,当应⽤需要获取Java对象时,使⽤get(final byte[]key)函数将字节数组取出,然后反序列化为Java对象即可。 和很多NoSQL数据库(例如Memcache、Ehcache)的客户端不同,Jedis本⾝没有提供序列化的⼯具,也就是说开发者需要⾃⼰引⼊序列化的⼯具。
4.在测试主机可以成功连接到虚拟机上的redis服务器并且可以存读数据后,考虑如何存读对象。
建⽴⼀个实现了Serializable接⼝的简单对象类Club:
package bigjun.iplab.jdk;
import java.io.Serializable;
import java.util.Date;
public class Club implements Serializable {
/**
* 其实序列化的作⽤是能转化成Byte流,然后⼜能反序列化成原始的类。能
* 在⽹络进⾏传输,也可以保存在磁盘中,
* 有了SUID之后,那么如果序列化的类已经保存了在本地中,
* 中途你更改了类后,SUID变了,那么反序列化的时候就不会变成原始的类了,
* 还会抛异常,主要就是⽤于版本控制。
*/
private static final long serialVersionUID = 1L;
private int id;
private String name;
private String info;
private Date createDate;
private int rank;
public Club() {
}
public Club(int id, String name, String info, Date createDate, int rank) {
super();
this.id = id;
this.name = name;
this.info = info;
this.rank = rank;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
public Date getCreateDate() {
return createDate;
}
public void setCreateDate(Date createDate) {
}
public int getRank() {
return rank;
}
public void setRank(int rank) {
this.rank = rank;
}
5.使⽤JDK库实现序列化和反序列化:
package bigjun.iplab.jdk;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Date;
import redis.clients.jedis.Jedis;
public class JDKSerializetionUtil {
public static void main(String[] args) {
Jedis jedis = null;
try {
jedis = new Jedis("192.168.131.130");
Club club = new Club();
club.setId(1);
club.setName("AC");
club.setInfo("⽶兰");
club.setCreateDate(new Date());
club.setRank(2);
jedis.set("JDK".getBytes(), serialize(club));
byte[] getByte = ("JDK".getBytes());
Object getObject = unserizlize(getByte);
if (getObject instanceof Club) {
System.out.println(getObject);
System.out.println(((Club) getObject).getId());
System.out.println(((Club) getObject).getName());
System.out.println(((Club) getObject).getInfo());
System.out.println(((Club) getObject).getCreateDate());
System.out.println(((Club) getObject).getRank());
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (jedis != null) {
jedis.close();
}
}
}
private static byte[] serialize(Object object) {
ObjectOutputStream objectOutputStream = null;
ByteArrayOutputStream byteArrayOutputStream = null;
try {
byteArrayOutputStream = new ByteArrayOutputStream();
objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(object);
byte[] getByte = ByteArray();
return getByte;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
private static Object unserizlize(byte[] binaryByte) {
ObjectInputStream objectInputStream = null;
ByteArrayInputStream byteArrayInputStream = null;
byteArrayInputStream = new ByteArrayInputStream(binaryByte);
try {
objectInputStream = new ObjectInputStream(byteArrayInputStream);
Object obj = adObject();
return obj;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
输出为:
bigjun.iplab.jdk.Club@300ffa5d
1
AC
⽶兰
Sun Jun 03 20:29:24 GMT+08:00 2018
2
在虚拟机上运⾏get JDK得到:
192.168.131.130:6379> get JDK
"\xac\xed\x00\x05sr\x00\x15bigjun.iplab.jdk.Club\x00\x00\x00\x00\x00\x00\x00\x01\x02\x00\x05I\x00\x02idI\x00\x04rankL\x00\ncreateDatet\x00\x10Ljava/util/Date;L\x00\x04infot\x00\x12Ljava/lang/String;L\x00\x04nameq\x00~\x00\x02xp\x00\x0 再来看⼀下序列化⽅法:
private static byte[] serialize(Object object) {
ObjectOutputStream objectOutputStream = null;
ByteArrayOutputStream byteArrayOutputStream = null;
try {
byteArrayOutputStream = new ByteArrayOutputStream();
objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(object);
byte[] getByte = ByteArray();
return getByte;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
ByteArrayOutputStream:
ObjectOutputStream:
再来看⼀下反序列⽅法:
private static Object unserizlize(byte[] binaryByte) {
ObjectInputStream objectInputStream = null;
ByteArrayInputStream byteArrayInputStream = null;
byteArrayInputStream = new ByteArrayInputStream(binaryByte);
try {
objectInputStream = new ObjectInputStream(byteArrayInputStream);
Object obj = adObject();
return obj;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
ByteArrayInputStream:
ObjectInputStream:
6.使⽤Xml实现序列化和反序列化
⾸先,必须要在要被序列化的对象的类上注释@XmlRootElement(name = "Club"),即:
package l;
import java.io.Serializable;
import java.util.Date;
l.bind.annotation.XmlRootElement;
// Xml⽂件中的根标识,必须要表明这个元素,可以让对象和Xml之间⽅便转换
@XmlRootElement(name = "Club")
public class Club implements Serializable {
...
}
然后是在Jedis中利⽤Xml读写Club对象:
package l;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.Date;
l.bind.JAXBContext;
l.bind.JAXBException;
l.bind.Marshaller;
l.bind.Unmarshaller;
import redis.clients.jedis.Jedis;
public class XMLSerializetionUtil {
public static void main(String[] args) {
Jedis jedis = null;
try {
jedis = new Jedis("192.168.131.130");
Club club = new Club();
club.setId(2);
club.setName("RM");
club.setInfo("皇马");
club.setCreateDate(new Date());
club.setRank(1);
jedis.set("XML", serialize(club));
String getString = ("XML");
Object getObject = unserizlize(Club.class, getString);
if (getObject instanceof Club) {
System.out.println(getObject);
System.out.println(((Club) getObject).getId());
System.out.println(((Club) getObject).getName());
System.out.println(((Club) getObject).getInfo());
System.out.println(((Club) getObject).getCreateDate());
System.out.println(((Club) getObject).getRank());
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (jedis != null) {
jedis.close();
}
}
}
private static String serialize(Object object) {
StringWriter stringWriter = null;
try {
stringWriter = new StringWriter();
JAXBContext jContext = Class());
Marshaller marshaller = ateMarshaller();
marshaller.marshal(object, stringWriter);
} catch (JAXBException e) {
e.printStackTrace();
}
String();
}
private static Object unserizlize(Class<Club> clazz, String xmlString) {
Object xmlObject = null;
try {
JAXBContext context = wInstance(clazz);
Unmarshaller unmarshaller = ateUnmarshaller();
StringReader stringReader = new StringReader(xmlString);
xmlObject = unmarshaller.unmarshal(stringReader);
} catch (JAXBException e) {
e.printStackTrace();
}
return xmlObject;
}
}
输出为:
l.Club@1f17ae12
2
RM
皇马
Mon Jun 04 09:42:17 GMT+08:00 2018
1
在虚拟机上运⾏get XML得到:
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><Club><createDate>2018-06-04T09:42:17.343+08:00</createDate><id>2</id><info>\xe7\x9a\x87\xe9\xa9\xac</info><name>RM</name><rank>1</rank></Club>" 再来分析⼀下序列化⽅法:
private static String serialize(Object object) {
StringWriter stringWriter = null;
try {
stringWriter = new StringWriter();
JAXBContext jContext = Class());
Marshaller marshaller = ateMarshaller();
marshaller.marshal(object, stringWriter);
} catch (JAXBException e) {
e.printStackTrace();
}
String();
}
再来分析⼀下反序列化⽅法:
private static Object unserizlize(Class<Club> clazz, String xmlString) {
Object xmlObject = null;
try {
JAXBContext context = wInstance(clazz);
Unmarshaller unmarshaller = ateUnmarshaller();
StringReader stringReader = new StringReader(xmlString);
xmlObject = unmarshaller.unmarshal(stringReader);
} catch (JAXBException e) {
e.printStackTrace();
}
return xmlObject;
}
7.使⽤JSON实现序列化和反序列化
Java下常⽤的JSON⼯具类库主要有以下⼏种:
JSON-lib
FastJson
Jackson
Gson
1.以JSON-lib为例:
所需的jar包为:
Club类不需要添加任何注释,直接看在Jedis中通过JSON读写Club对象类:
package bigjun.iplab.json;
import java.util.Date;
import ph.object.DateMorpher;
import net.sf.json.JSONObject;
import net.sf.json.util.JSONUtils;
import redis.clients.jedis.Jedis;
public class JDKSerializetionUtil {
public static void main(String[] args) {
Jedis jedis = null;
try {
jedis = new Jedis("192.168.131.130");
Club club = new Club();
club.setId(3);
club.setName("CLE");
club.setInfo("骑⼠");
club.setCreateDate(new Date());
club.setRank(2);
jedis.set("JSON", serialize(club));
String getByte = ("JSON");
Object getObject = unserizlize(getByte);
if (getObject instanceof Club) {
System.out.println(getObject);
System.out.println(((Club) getObject).getId());
System.out.println(((Club) getObject).getName());
System.out.println(((Club) getObject).getInfo());
System.out.println(((Club) getObject).getCreateDate());
System.out.println(((Club) getObject).getRank());
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (jedis != null) {
jedis.close();
}
}
}
private static String serialize(Object object) {
JSONObject jsonObject = JSONObject.fromObject(object);
String getString = String();
return getString;
}
private static Object unserizlize(String jsonString) {
new JSONObject();
JSONObject jObject = JSONObject.fromObject(jsonString);
Object jsonObject = Bean(jObject, Club.class);
return jsonObject;
}
}
输出为:
六⽉ 04, 2018 11:02:31 上午 net.sf.json.JSONObject toBean
信息: Property 'day' of class java.util.Date has no write method. SKIPPED.
六⽉ 04, 2018 11:02:31 上午 net.sf.json.JSONObject toBean
信息: Property 'timezoneOffset' of class java.util.Date has no write method. SKIPPED.
bigjun.iplab.json.Club@2a098129
3
CLE
骑⼠
Mon Jun 04 11:02:30 GMT+08:00 2018
2
在Redis服务器所在的虚拟机上执⾏get JSON输出为:
192.168.131.130:6379> get JSON
"{\"createDate\":{\"date\":4,\"day\":1,\"hours\":11,\"minutes\":2,\"month\":5,\"seconds\":30,\"time\":1528081350946,\"timezoneOffset\":-480,\"year\":118},\"id\":3,\"info\":\"\xe9\xaa\x91\xe5\xa3\xab\",\"name\":\"CLE\",\"rank\":2}" 分析使⽤JSON实现序列化代码:将Java对象转换为JSON对象--将JSON对象转换为String类型的字符串。
private static String serialize(Object object) {
JSONObject jsonObject = JSONObject.fromObject(object);
String getString = String();
return getString;
}
分析使⽤JSON实现反序列化代码:将String类型的JSON字符串转换为JSON对象----将JSON对象转换为Java对象。
private static Object unserizlize(String jsonString) {
new JSONObject();
JSONObject jObject = JSONObject.fromObject(jsonString);
// 防⽌转换时间错误java xml是什么
Object jsonObject = Bean(jObject, Club.class);
return jsonObject;
}
2.以FastJson为例:
(1)FastJson介绍
Fastjson是⼀个Java语⾔编写的⾼性能功能完善的JSON库。它采⽤⼀种“假定有序快速匹配”的算法,把JSON Parse的性能提升到极致,是⽬前Java语⾔中最快
的JSON库。Fastjson接⼝简单易⽤,已经被⼴泛使⽤在缓存序列化、协议交互、Web输出、Android客户端等多种应⽤场景。
(2)FastJson优点:
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论