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
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 被用来表明类的不同版本间的兼容性