[转载]Enterprise JavaBeans 入门:序 列 化

Enterprise JavaBeans 入门

序 列 化


本章讲述内容

  • 序列化并不是完全自动的
  • 序列化必需要定制



回页首


Bean 的引用不会序列化

自己试一下

Seems to work...
BankAccount account = getBankAccountHome().findById(42);
ObjectOutputStream out = new ObjectOutputStream(...);
out.writeObject(account);
out.close();

You should get an exception when you attempt to send a message
ObjectInputStream in = new ObjectInputStream(...);
BankAccount account = (BankAccount)in.readObject();
in.close();
account.getBalance();




回页首


解决方案: 使用 Handle

BankAccount account = getBankAccountHome().findById(42);
ObjectOutputStream out = new ObjectOutputStream(...);
out.writeObject(account.getHandle());
out.close();

ObjectInputStream in = new ObjectInputStream(...);
Handle handle = (Handle)in.readObject();
BankAccount account = (BankAccount)handle.getEJBObject();
in.close();
account.getBalance();




回页首


问题: Bean 引用 Bean

不是一个真正的问题
服务器自动地处理对其它 Bean 的直接引用
public class BankAccountBean implements EntityBean {
public int id;
public double balance;
public Customer owner;
...
}




回页首


问题: Bean 引用一组 Bean

对 Bean 的间接的引用 (通过一个 Collection) 不是能够由服务器来处理的
我们必需提供定制的序列化
public class CustomerBean implements EntityBean {
public int id;
public Vector accounts;
...
}




回页首


定制序列化

  • 可序列化对象可以调整它序列化的方式
  • 域可以被标记为 "transient"
    • "transient" 意味着 "不要序列化"
    • 这些域在序列化时被忽略,在反序列化时为空
  • 特殊的方法:
    • writeObject() - 为实例提供定制的序列化
    • readObject() - 为实例提供定制的反序列化



回页首


一个示例

  • 序列化未编码的口令是潜在的安全问题
  • 考虑 User
    • 可序列化
    • "password" 域被标记为 "transient"
import java.io.*;
public class User implements Serializable {
private String name;
private transient String password;
...
}




回页首


一个示例: writeObject()

  • 调用 defaultWriteObject() 来自动地序列化所有的 non-transient 域
  • 自己处理特殊的域
private void writeObject(ObjectOutputStream out) 
throws IOException {
out.defaultWriteObject();
out.writeObject(encode(getPassword()));
}




回页首


一个示例: readObject()

  • 调用 defaultReadObject() 来自动地反序列化所有的 non-transient 域
  • 自己处理特殊的域
private void readObject(ObjectInputStream in) 
throws ClassNotFoundException, IOException {
in.defaultReadObject();
setPassword(decode((String)in.readObject()));
}




回页首


序列化 Bean 引用

  • Handle 可以作为 Bean 引用序列化的替代
  • 但是... 哪个类应该来实现定制的序列化呢?
    • Bean 类本身不序列化
    • 我们也不能扩展 Vector 类




回页首


引入一个中间对象 Object

  • 通常总是需要的
  • 中间对象可以提供定制的序列化
private void writeObject(ObjectOutputStream out) 
throws IOException {
out.defaultWriteObject();
out.writeObject(getBean().getHandle());
}




回页首


但是稍等一下... 还有更多的问题

  • serialVersionUID 域是不同版本间兼容的标记
  • 例如:
    • 创建一个类的实例
    • 序列化它
    • 修改此类 (添加/删除 non-static 域)
    • 反序列化
  • 发生了什么?
    不兼容版本的异常被抛出



回页首


版本兼容性

  • 同一个类的不兼容版本有不同的 serialVersionUID
    • 如果您不提供一个值,将回自动产生一个
    • 生成的值是基于类的"形状"
  • 如果值匹配,反序列化过程将为存在的域尽量提供值
  • 只有同时存在于两个版本的域才会被恢复
    • 当前版本所没有的域被忽略
    • 当前版本新出现的域被置空



回页首


您应该如何设定此值?

  • SerialVer 工具可以用来生成一个 id
    • id 存放在 static final 的域中

    public class BankAccount implements Serializable {
    static final long serialVersionUID = 3206093459760846163L;
    ...
    }

本章讲述内容

  • readObject() 和 writeObject() 可以用来提供定制的序列化功能
  • That references between beans are possible--But that they must be managed
  • serialVersionUID 被用来表明类的不同版本间的兼容性
请使用浏览器的分享功能分享到微信等