javabean持久化的原理与应用举例
javabean持久化是指以流的形式,用javaBean的属性来保存bean,并在以后在本地读取或从其他JVM中读取他保存的属性信息;
这和对象序列化类似,但区别是:JavaBean持久化适合于长期存储,而对象序列化只是短期的存储,会随着类程序版本的升级而过时;
对象序列化后,他的实例域都写入一个流中,如果类的实现更新了,并且他的实例域也更新了,这样就不能通过反射机制直接读取包含了过时版本的序列化对象数据,此时技术上可以实现新旧数据的同步但非常麻烦,只有在无路可走的时候才使用此方法,所以说,对象序列化不适合长期存储,典型的实例:
javax下的swing组件在其文档中都有类似的警告:‘该类的序列化对象与未来版本的Swing不兼容,当前对象序列化的支持仅适合与短期存储或者应用程序之间的RMI’;
为了解决这个问题,产生了长期存储机制,最初是为了拖拽GUI设计工具,来保存一系列的鼠标操作的结果,以便下次运行程序时保持前面操作的状态;
https://bean-builder.dev.java.net的Bean Builder是一个实验性的GUI工具,支持长期持久化;
——-持久化的原理:
1.构造窗体的源代码:
JFrame frame = new JFrame(); // 默认的构造器完成大部分的初始化工作
frame.setTitle(“My Application”); // 定义Title属性;
frame.setVisible(true); // 设置窗体可见性;
// 可以发现需要手工自定义的属性很少,
2.javaBean持久化机制:
将构造窗体和设置属性的源代码用XML语言精确描述:
javaBean类文件—>XML标准文档:此过程是由XMLEncoder操作完成的;
他所关心的是对某个对象设置了哪些属性,而对使用默认值的属性不予处理;
但对于不是基于类的属性的设置:frame.setSize(600, 400);
这里面涉及到坐标原点和坐标,XMLEncoder将如下给予处理:
// 这样,XMLEncoder完成了格式化java类为xml描述文件的操作流的工作;
XMLEncoder out = new XMLEncoder(new FileOutputStream(保存文件));
out.writeObject(frame); // 类似对象序列化,将对象写入流
out.close(); // 写完关闭输出流,可见,XMLEncoder是一种输出流,具有格式化功能;
3.将保存的xml文件中描述的类的状态信息还原,需要借助XMLDecoder类,
XMLDecoder in = new XMLDecoder(new FileInputStream(接收的文件)); // 这与上面是完全相反的操作;
JFrame newFrame = (JFrame)in.readObject(); // 从流中读取并返回object类型的对象,向下转型是必须的;
in.close(); // 读完关闭输入流,可见XMLDecoder是一种xml格式的解码器,操作输入流;
———-实例:
import java.awt.*;
import java.awt.event.*;
import java.beans.*;
import java.io.*;
import javax.swing.*;
/**
此程序演示XML编码器和XML解码器存取一个窗体的使用,
*/
public class PersistentFrameTest
{
public static void main(String[] args)
{
chooser = new JFileChooser(); // 选择器组件
chooser.setCurrentDirectory(new File(“.”)); // 设置当前目录
PersistentFrameTest test = new PersistentFrameTest(); // 实例化本实例
test.init(); // 调用本实例初始化方法;
}
public void init() // 初始化方法
{
frame = new JFrame(); // 一个默认窗体
frame.setLayout(new FlowLayout()); // 设置流布局
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 窗体在关闭是退出
frame.setTitle(“PersistentFrameTest”); // 窗体名称
frame.setSize(400, 200); // 窗体的纵横坐标值,分别表示长和宽
JButton loadButton = new JButton(“Load”); // 按钮组件,
frame.add(loadButton); // 添加按钮到窗体面板
loadButton.addActionListener(EventHandler.create(ActionListener.class, this, “load”)); // 添加事件监听器,反射机制,调用load方法
JButton saveButton = new JButton(“Save”); // 按钮组件,
frame.add(saveButton); // 添加按钮到窗体面板
saveButton.addActionListener(EventHandler.create(ActionListener.class, this, “save”)); // 添加事件监听器,反射机制,调用save方法
frame.setVisible(true); // 窗体默认都是不可见的;
}
public void load() // 定义load按钮的操作
{
// 显示文件选择器记录
int r = chooser.showOpenDialog(null);
// 如果文件被选择了,打开
if (r == JFileChooser.APPROVE_OPTION)
{
try
{
File file = chooser.getSelectedFile(); // 获取选择的文件
XMLDecoder decoder = new XMLDecoder(new FileInputStream(file)); // 从选择文件中解码
JFrame newFrame = (JFrame)decoder.readObject();
decoder.close(); // 读完关闭
}
catch (IOException e)
{
JOptionPane.showMessageDialog(null, e);
}
}
}
public void save() // 定义save按钮的操作
{
// 显示文件选择器记录
int r = chooser.showOpenDialog(null);
// 如果文件被选择了,打开
if (r == JFileChooser.APPROVE_OPTION)
{
try
{
File file = chooser.getSelectedFile(); // 获取选择的文件
XMLEncoder encoder = new XMLEncoder(new FileOutputStream(file)); // 将格式化的xml输入被选择文件中
encoder.writeObject(frame); // 将当前窗体对象进行持久化操作,转换为xml描述
encoder.close(); // 写完关闭
}
catch (IOException e)
{
JOptionPane.showMessageDialog(null, e);
}
}
}
private static JFileChooser chooser; // 静态意味着共享一个实例
private JFrame frame;
}
// 可以发现打开的窗体和原来的窗体一样;
———持久化的应用场合:
1.不能直接设置当前对象的状态,往往是因为没有setter方法,或者是为了安全一开始生成对象就不允许对对象的状态再设置,对象的状态必须保存下来,比如,公司的员工的基本信息一旦确定就无法更改,更改是不允许的,但这些信息必须被
长期的保存下来,这个过程就是持久化;
2.如果可以通过设置属性得到对象的状态,没有必要使用JavaBean持久化,还有一种情况:是为了保存对象在某一时段的
状态,比如,IDE的可视化编程,每次的操作结果都被后台记录并保存,下次打开不必一切从头来!
对于没有setter方法的类,需要构造一个持久化代理(persistence delegate)完成对象的保存;
XMLWriter中要设置这个持久化代理;
// xml编码
XMLEncoder e = new XMLEncoder(
new BufferedOutputStream(
new FileOutputStream(“Test.xml”)));
e.writeObject(new JButton(“Hello, world”));
e.close();
// xml解码:
XMLDecoder d = new XMLDecoder(
new BufferedInputStream(
new FileInputStream(“Test.xml”)));
Object result = d.readObject();
d.close();
// 设置持久化代理:
import java.awt.geom.*;
import java.beans.*;
import java.net.*;
import java.util.*;
/**
* 此程序验证各种情况的持久化代理.
*
*/
public class PersistenceDelegateTest
{
public static class Point // 静态内部类,不必实例化外部类,直接引用
{
@ConstructorProperties( { “x”, “y” })
public Point(int x, int y) // 一个点的坐标
{
this.x = x;
this.y = y;
}
public int getX()
{
return x;
}
public int getY()
{
return y;
}
private final int x, y; // 对一个点,他的坐标是固定不变的
}
public static void main(String[] args) throws Exception
{
PersistenceDelegate delegate = new PersistenceDelegate() // 实例化持久化代理,
{
protected Expression instantiate(Object oldInstance, Encoder out) // 实例化时覆写持久化代理的方法
{
Employee e = (Employee) oldInstance; // oldInstance引用的是被持久化的对象,但该引用是Object类型,
GregorianCalendar c = new GregorianCalendar(); // 实例化日期类
c.setTime(e.getHireDay()); // get方法说明hireDay属性可以直接访问
return new Expression(oldInstance, Employee.class, “new”, new Object[] {
e.getName(), e.getSalary(), c.get(Calendar.YEAR), c.get(Calendar.MONTH),
c.get(Calendar.DATE) }); // 返回值是一个Expression类型,对oldInstance对象执行Employee类型的反射,调用new方法,其要保存的属性是保存在Object数组中成员,这借助于反射机制
}
};
// BeanInfo info = Introspector.getBeanInfo(Employee.class); // BeanInfo设置一个类对象的若干信息:方法,属性等
// info.getBeanDescriptor().setValue(“persistenceDelegate”, delegate); // 设置该beaninfo类型的
BeanInfo info = Introspector.getBeanInfo(DamageReport.class);
for (PropertyDescriptor desc : info.getPropertyDescriptors())
if (desc.getName().equals(“removeMode”))
desc.setValue(“transient”, Boolean.TRUE); // 属性removeMode不被持久化保存
XMLEncoder out = new XMLEncoder(System.out); // 准备持久化输出流
out.setExceptionListener(new ExceptionListener()
{
public void exceptionThrown(Exception e)
{
e.printStackTrace();
}
});
out.setPersistenceDelegate(Rectangle2D.Double.class, new DefaultPersistenceDelegate(
new String[] { “x”, “y”, “width”, “height” })); // 1.设置持久化代理,指定属性和类
out.setPersistenceDelegate(Inet4Address.class, new DefaultPersistenceDelegate()
{// 2.设置持久化代理,通过覆写默认持久化代理的实例化方法,
protected Expression instantiate(Object oldInstance, Encoder out)
{
return new Expression(oldInstance, InetAddress.class, “getByAddress”,
new Object[] { ((InetAddress) oldInstance).getAddress() });
}
});
out.setPersistenceDelegate(BitSet.class, new DefaultPersistenceDelegate()
{// 3.通过覆写默认持久化代理的初始化方法设置持久化代理
protected void initialize(Class> type, Object oldInstance, Object newInstance,
Encoder out)
{
super.initialize(type, oldInstance, newInstance, out);
BitSet bs = (BitSet) oldInstance;
for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i + 1))
out.writeStatement(new Statement(bs, “set”, new Object[] { i, i + 1, true }));
}
});
// 将持久化对象保存
out.writeObject(new Employee(“Harry Hacker”, 50000, 1989, 10, 1));
out.writeObject(new Point(17, 29));
out.writeObject(new java.awt.geom.Rectangle2D.Double(5, 10, 20, 30));
out.writeObject(InetAddress.getLocalHost());
BitSet bs = new BitSet(); // 位集
bs.set(1, 4); // 设置1-4位为true:1111
bs.clear(2, 3); // 第2-3为复位:1001
out.writeObject(bs); // 保存当前位集状态:1001
out.close();
}
}
// 用到的Employee类:
import java.util.*;
public class Employee
{
public Employee(String n, double s, int year, int month, int day)
{
name = n;
salary = s;
GregorianCalendar calendar = new GregorianCalendar(year, month – 1, day);
// GregorianCalendar uses 0 for January
hireDay = calendar.getTime();
}
public Employee(String n, double s, Date h)
{
name = n;
salary = s;
hireDay = h;
}
public String getName() // 雇员的信息在雇用时(初始化)就已经确定,不允许以后修改和有修改的途径;只能读取;
{
return name;
}
public double getSalary()
{
return salary;
}
public Date getHireDay()
{
return hireDay;
}
public void raiseSalary(double byPercent)
{
double raise = salary * byPercent / 100;
salary += raise;
}
private String name;
private double salary;
private Date hireDay;
}
声明: 除非转自他站(如有侵权,请联系处理)外,本文采用 BY-NC-SA 协议进行授权 | 嗅谱网
转载请注明:转自《javabean持久化的原理与应用举例》
本文地址:http://www.xiupu.net/archives-208.html
关注公众号:
微信赞赏
支付宝赞赏