Java 序列化对象的一个使用案例

Effective Java》中序列化一节关于java的序列化存在如下说法:

对象序列化(object serialization)API,它提供了一个框架,用来将对象编码成字节流(serializing),并从字节流编码中重新构建对象(deserializing)。一旦对象被序列化后,它的编码就可以从一台正在运行的jvm传到另一台jvm上,或者被存储在磁盘上,供以后反序列化时用(如tomcat的session的可持久化)。序列化技术为远程通信提供了标准的线路级对象表示法,也为JavaBeans组件结构提供了标准的持久化数据格式。

关于java序列化,看过不少资料,一直没有完全搞明白里面的奥义,正好最近在重读Effective Java,然后加上这两天碰到一个需求,能很好的诠释序列化,所以在这边小结下。

需求:系统中自己写了个内存缓存cache,然后集群内每个节点都单独维护自己各自的内存缓存(ps:有人肯定该说艾斯比,怎么不用Memcached或者Redis,么法,leader的要求…… ),这个内存缓存其实就是基于Map的,key=String,value=Object对象。cache需要提供这样一个方法,要能够刷新集群内所有节点的map中单个KV。

分析如上需求,map中value保存的是Object,这个Object并不是一般的String之类的,而恰恰就是一个真正名符其实的JavaBean对象,刷新时,需要将新的bean发送各节点,由各节点再各自操作内存中的map。这样,就出现了雏形,各节点需要提供一个http接口,刷新时,将bean对象发到到http上,这样就形成了上述Effective Java说到的场景,为远程通信提供标准的线路级对象表示法,也即将Object
bean以stream的形式post到http接口,http接口接到stream后,将stream反序列化成bean对象。

代码实现如下:

javabean就不列了,是一个很纯粹的bean类,只不过该类一定是序列化后的(关于序列化的高级进阶请参考Effective Java),笔者这里只implements Serializable即可满足需求。

http post 工具类:

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

/**
 * Http 请求访问工具类
 *
 * @author will_awoke
 * @version 2014-6-26
 * @see HttpAccessUtil
 * @since
 */
public class HttpAccessUtil
{

    /**
     * 日志
     */
    private static Logger log = Logger.getLogger(HttpAccessUtil.class);

    /**
     * 采取post方式提交序列化后的object对象 </br>
     * 另请参考:java.io.ObjectInputStream/ObjectOutputStream
     * @param requestUrl 请求地址
     * @param connTimeoutMills 设置连接主机超时,单位:毫秒
     * @param readTimeoutMills 设置从主机读取数据超时,单位:毫秒
     * @param serializedObject 序列化后的object对象
     *
     * @return remoteHttp返回的结果
     */
    public static String httpPostSerialObject(String requestUrl, int connTimeoutMills,
                                              int readTimeoutMills, Object serializedObject) throws Exception
    {
        HttpURLConnection httpUrlConn = null;
        InputStream inputStream = null;
        InputStreamReader inputStreamReader = null;
        BufferedReader bufferedReader = null;
        ObjectOutputStream oos = null;
        StringBuffer buffer = new StringBuffer();
        try
        {
            URL url = new URL(requestUrl);
            httpUrlConn = (HttpURLConnection)url.openConnection();
            // 设置content_type=SERIALIZED_OBJECT
            // 如果不设此项,在传送序列化对象时,当WEB服务默认的不是这种类型时可能抛java.io.EOFException
            httpUrlConn.setRequestProperty("Content-Type","application/x-java-serialized-object");
            httpUrlConn.setConnectTimeout(connTimeoutMills);
            httpUrlConn.setReadTimeout(readTimeoutMills);
            // 设置是否向httpUrlConn输出,因为是post请求,参数要放在http正文内,因此需要设为true, 默认情况下是false
            httpUrlConn.setDoOutput(true);
            // 设置是否从httpUrlConn读入,默认情况下是true
            httpUrlConn.setDoInput(true);
            // 不使用缓存
            httpUrlConn.setUseCaches(false);

            // 设置请求方式,默认是GET
            httpUrlConn.setRequestMethod("POST");
            httpUrlConn.connect();

            if (serializedObject != null)
            {
                // 此处getOutputStream会隐含的进行connect,即:如同调用上面的connect()方法,
                // 所以在开发中不调用上述的connect()也可以,不过建议最好显式调用
                // write object(impl Serializable) using ObjectOutputStream
                oos = new ObjectOutputStream(httpUrlConn.getOutputStream());
                oos.writeObject(serializedObject);
                oos.flush();
                // outputStream不是一个网络流,充其量是个字符串流,往里面写入的东西不会立即发送到网络,
                // 而是存在于内存缓冲区中,待outputStream流关闭时,根据输入的内容生成http正文。所以这里的close是必须的
                oos.close();
            }
            // 将返回的输入流转换成字符串
            // 无论是post还是get,http请求实际上直到HttpURLConnection的getInputStream()这个函数里面才正式发送出去
            inputStream = httpUrlConn.getInputStream();//注意,实际发送请求的代码段就在这里
            inputStreamReader = new InputStreamReader(inputStream, "UTF-8");
            bufferedReader = new BufferedReader(inputStreamReader);

            String str = null;
            while ((str = bufferedReader.readLine()) != null)
            {
                buffer.append(str);
            }
        }
        catch (Exception e)
        {
            log.error(requestUrl + " error ", e);
            throw e;
        }
        finally
        {
            try
            {
                IOUtils.closeQuietly(bufferedReader);
                IOUtils.closeQuietly(inputStreamReader);
                IOUtils.closeQuietly(inputStream);
                IOUtils.closeQuietly(oos);
                if (httpUrlConn != null)
                {
                    httpUrlConn.disconnect();
                }
            }
            catch (Exception e)
            {
                log.error(e);
            }
        }
        return buffer.toString();
    }

}

这里有点要着重说明下,httpConnect的Content-Type的一定要设置为application/x-java-serialized-object,否则http接口处在接收stream的时候会出现java.io.EOFException。另外:输出对象使用的是ObjectOutputStream的writeObject方法。

http接口接收stream,并反序列化为Object bean即可:

//read object from stream 反序列化将stream生成Object对象
ObjectInputStream ois = new ObjectInputStream(req.getInputStream());//HttpServletRequest req对象
Object value = ois.readObject();

后面就是replace map了,不再赘述。

总之,通过这个需求算是进一步了解了java序列化的作用 :)

时间: 2024-07-28 19:15:43

Java 序列化对象的一个使用案例的相关文章

java序列化对象简单理解

1. 什么是Java对象序列化 Java平台允许我们在内存中创建可复用的Java对象,但一般情况下,只有当JVM处于运行时,这些对象才可能存在,即,这些对象的生命周期不会比JVM的生命周期更长.但在现实应用中,就可能要求在JVM停止运行之后能够保存(持久化)指定的对象,并在将来重新读取被保存的对象.Java对象序列化就能够帮助我们实现该功能. 使用Java对象序列化,在保存对象时,会把其状态保存为一组字节,在未来,再将这些字节组装成对象.必须注意地是,对象序列化保存的是对象的"状态",

关于java序列化中的一个细节

java序列化机制的可以参考很多资料了,最近在看的时候发现了一些问题. 1. 默认的序列化机制,很多书里讲到序列化类只序列化类名,实例变量,不会实例化类变量(static)和瞬态变量(transient). 我使用1.6,1.7,1.8测试了一下,static都是可以被序列化的. 测试代码: 1 public class Logg implements Serializable{ 2 3 private static String name; 4 private transient String

Java序列化技术与Protobuff

前言: Java序列化是Java技术体系当中的一个重要议题,序列化的意义在于信息的交换和存储,通常会和io.持久化.rmi技术有关(eg:一些orm框架会要求持久化的对象类型实现Serializable接口). 本文将提供Java自带序列化机制和ProtoStuff的序列化(仅仅当作一种数据格式)的比较,从序列化的内容和特点来对二者进行比较. 结论:1,Java序列化对象时不需要通过属性的get set方法或其它无关序列化内部定义的方法(比如readObject,writeObject是内置的序

序列化 — Java序列化

一.序列化定义 Wike中对序列化的定义如下: In computing, serialization (or serialisation) is the process of translating data structures or object state into a format that can be stored (for example, in a file or memory buffer) or transmitted (for example, across a netw

JAVA面向对象 对象/引用

本页面更新日期: 2016年07月17日 对象/引用 在前面 PersonTest.java 代码中, 有这样一行代码: Person p = new Person(); 这行代码创建了一个 Person 实例, 也被称为 Person对象,这个Person对象被赋给 p 变量. 这行代码实际产生了两个东西: 一个是 p 变量, 一个是 Person 对象. 从 Person 类定义来看, Person 对象应包含两个实例变量, 而变量时需要内存来存储的. 因此, 当创建 Person 对象时,

spring mvc返回json字符串数据,只需要返回一个java bean对象就行,只要这个java bean 对象实现了序列化serializeable

1.spring mvc返回json数据,只需要返回一个java bean对象就行,只要这个java bean 对象实现了序列化serializeable 2. @RequestMapping(value = { "/actor_details" }, method = { RequestMethod.POST }) @ResponseBody public ResultObject actorDetails(@RequestBody ActorDetailsRequest req)

Java实现对象的序列化

什么是对象的序列化? 序列化:把对象转化成字节序列的过程就是对象的序列化:反序列化:把字节序列转化成对象的过程就是对象的反序列化.单看概念比较抽象,但是看代码就会明白. 对象序列化的用途 1.Java程序在运行中,对象都是分配在内存中,而序列化的一个用途就是将内存的中对象转化成磁盘中的对象. 2.对象不能直接在网络中传输,有时候需要将对象转成字节序列在网络中传输,这就是对象序列化的第二个用途. 如何实现对象的序列化? 1.新建一个实体对象,实现Serializable接口,这个实体对象就可以进行

Java将对象写入文件读出——序列化与反序列化

Java类中对象的序列化工作是通过ObjectOutputStream和ObjectInputStream来完成的. 写入: 1 File aFile=new File("e:\\c.txt"); 2 Stu a=new Stu(1, "aa", "1"); 3 FileOutputStream fileOutputStream=null; 4 try { 5 fileOutputStream = new FileOutputStream(aFi

java序列化之后,对象的引用关系?

今天写代码的时候用到序列化,不过突然想到这个问题. 于是写了一些测试代码,得出两个结论. 如果两个对象存在引用关系,比如A引用B. 如果两个对象是各自序列化的,则引用关系不再存在. 如果两个对象是是另一个类对象C的成员,序列化C,反序列化C之后,A和B的引用关系还存在. 我就是做了这个两个实验. 1 node2引用了node1,node2.parent=node1, 序列化和反序列化之后, 发现node2.parent !=node1. node2.parent 指向的内存跟node1不同,而是