- 浏览: 44846 次
- 性别:
- 来自: 广州
文章分类
最新评论
来源:http://book.51cto.com/art/201202/317465.htm
部分属性持久化问题看似很简单,只要把不需要持久化的属性加上瞬态关键字(transient关键字)即可。这是一种解决方案,但有时候行不通。例如一个计税系统和人力资源系统(HR系统)通过RMI(Remote Method Invocation,远程方法调用)对接,计税系统需要从HR系统获得人员的姓名和基本工资,以作为纳税的依据,而HR系统的工资分为两部分:基本工资和绩效工资,基本工资没什么秘密,根据工作岗位和年限自己都可以计算出来,但绩效工资却是保密的,不能泄露到外系统,很明显这是两个相互关联的类。先来看薪水类Salary类的代码:
public class Salary implements Serializable{ private static final long serialVersionUID = 44663L; //基本工资 private int basePay; //绩效工资 private int bonus; public Salary(int _basePay,int _bonus){ basePay = _basePay; bonus = _bonus; } /*getter/setter方法省略*/ }
Peron类与Salary类是关联关系,代码如下:
public class Person implements Serializable{ private static final long serialVersionUID =60407L; //姓名 private String name; //薪水 private Salary salary; public Person(String _name,Salary _salary){ name=_name; salary=_salary; } /*getter/setter方法省略*/ }
这是两个简单的JavaBean,都实现了Serializable接口,都具备了持久化条件。首先计税系统请求HR系统对某一个Person对象进行序列化,把人员和工资信息传递到计税系统中,代码如下:
public class Serialize { public static void main(String[] args) { //基本工资1000元,绩效工资2500元 Salary salary = new Salary(1000,2500); //记录人员信息 Person person = new Person("张三",salary); //HR系统持久化,并传递到计税系统 SerializationUtils.writeObject(person); } }
在通过网络传送到计税系统后,进行反序列化,代码如下:
public class Deserialize { public static void main(String[] args) { //技术系统反序列化,并打印信息 Person p = (Person)SerializationUtils.readObject(); StringBuffer sb = new StringBuffer(); sb.append("姓名:" + p.getName()); sb.append("\t基本工资:" + p.getSalary().getBasePay()); sb.append("\t绩效工资:" + p.getSalary().getBonus()); System.out.println(sb); } }
打印出的结果很简单:
- 姓名:张三 基本工资:1000 绩效工资:2500。
但是这不符合需求,因为计税系统只能从HR系统中获得人员姓名和基本工资,而绩效工资是不能获得的,这是个保密数据,不允许发生泄露。怎么解决这个问题呢?你可能马上会想到四种方案:
(1)在bonus前加上transient关键字
这是一个方法,但不是一个好方法,加上transient关键字就标志着Salary类失去了分布式部署的功能,它可是HR系统最核心的类了,一旦遭遇性能瓶颈,想再实现分布式部署就不可能了,此方案否定。
(2)新增业务对象
增加一个Person4Tax类,完全为计税系统服务,就是说它只有两个属性:姓名和基本工资。符合开闭原则,而且对原系统也没有侵入性,只是增加了工作量而已。这是个方法,但不是最优方法。
(3)请求端过滤
在计税系统获得Person对象后,过滤掉Salary的bonus属性,方案可行但不合规矩,因为HR系统中的Salary类安全性竟然让外系统(计税系统)来承担,设计严重失职。
(4)变更传输契约
例如改用XML传输,或者重建一个 Web Service服务。可以做,但成本太高。
可能有读者会说了,你都在说别人的方案不好,你提供个优秀的方案看看!好的,这就展示一个优秀的方案。其中,实现了Serializable接口的类可以实现两个私有方法:writeObject和readObject,以影响和控制序列化和反序列化的过程。我们把Person类稍做修改,看看如何控制序列化和反序列化,代码如下:
public class Person implements Serializable{ private static final long serialVersionUID =60407L; //姓名 private String name; //薪水 private transient Salary salary; public Person(String _name,Salary _salary){ name=_name; salary=_salary; } //序列化委托方法 private void writeObject(java.io.ObjectOutputStream out) throws IOException { out.defaultWriteObject(); out.writeInt(salary.getBasePay()); } //反序列化时委托方法 private void readObject(java.io.ObjectInputStream in) throws IOException,ClassNotFoundException { in.defaultReadObject(); salary = new Salary(in.readInt(),0); } }
其他代码不做任何改动,我们先运行看看,结果为:
- 姓名:张三 基本工资:1000 绩效工资:0 。
我们在Person类中增加了writeObject和readObject两个方法,并且访问权限都是私有级别,为什么这会改变程序的运行结果呢?其实这里使用了序列化独有的机制:序列化回调。Java调用ObjectOutputStream类把一个对象转换成流数据时,会通过反射(Reflection)检查被序列化的类是否有writeObject方法,并且检查其是否符合私有、无返回值的特性。若有,则会委托该方法进行对象序列化,若没有,则由ObjectOutputStream按照默认规则继续序列化。同样,在从流数据恢复成实例对象时,也会检查是否有一个私有的readObject方法,如果有,则会通过该方法读取属性值。此处有几个关键点要说明:
(1)out.defaultWriteObject()
告知JVM按照默认的规则写入对象,惯例的写法是写在第一句话里。
(2)in.defaultReadObject()
告知JVM按照默认规则读入对象,惯例的写法也是写在第一句话里。
(3)out.writeXX和in.readXX
分别是写入和读出相应的值,类似一个队列,先进先出,如果此处有复杂的数据逻辑,建议按封装Collection对象处理。
可能有读者会提出,这似乎不是一种优雅的处理方案呀,为什么JDK没有对此提供一个更好的解决办法呢?比如访问者模式,或者设置钩子函数(Hook),完全可以更优雅地解决此类问题。我查阅了大量的文档,得出的结论是:无解,只能说这是一个可行的解决方案而已。
再回到我们的业务领域,通过上述方法重构后,其代码的修改量减少了许多,也优雅了许多。可能你又要反问了:如此一来,Person类也失去了分布式部署的能力啊。确实是,但是HR系统的难点和重点是薪水计算,特别是绩效工资,它所依赖的参数很复杂(仅从数量上说就有上百甚至上千种),计算公式也不简单(一般是引入脚本语言,个性化公式定制),而相对来说Person类基本上都是“静态"属性,计算的可能性不大,所以即使为性能考虑,Person类为分布式部署的意义也不大。
发表评论
-
职场观察:高薪需要什么?
2014-04-01 21:07 361http://xjsunjie.blog.51cto.com ... -
毕业五年来的回顾
2014-04-01 20:59 329http://luogangan.blog.51cto.co ... -
深处跳槽热浪中,跳与不跳该如何抉择?
2013-03-20 13:02 646深处跳槽热浪中,跳与不跳该如何抉择? 跳槽有哪些技巧和注意事项 ... -
面试 需要注意三种公司
2013-03-20 12:55 594来源:http://cuisuqiang.iteye.com ... -
面试 需要警惕三个问题
2013-03-20 12:54 553来源:http://cuisuqiang.ite ... -
离职 需要注意三个问题
2013-03-20 12:53 593来源:http://cuisuqiang.ite ... -
最具争议的10个编程观点
2013-02-12 22:21 652你认为最具争议的编程观点是什么?C#专家Jon Skeet曾 ... -
Java枚举的七种常见用法
2013-01-06 12:19 647http://blog.jobbole.com/31597/ ... -
设计高可用和高负载的网站系统
2012-12-10 12:57 562随着网站的运营,用户 ... -
大型互联网网站架构心得
2012-12-10 12:52 630大型互联网网站架构心 ... -
世界最大的PHP站点 Facebook后台技术探秘
2012-12-10 12:49 708在今年举行的Facebook F8开发者大会上,51CTO带您 ... -
为程序员量身定制的12个目标
2012-11-18 15:44 646http://justjavac.iteye.com/b ... -
Java资源同步的方式
2012-10-25 08:30 777前面我们知道syncnized方法可以对一段代码进行资源 ... -
FusionCharts:Div层被Flash遮住
2012-10-20 17:34 643http://www.zihou.me/html/201 ... -
FusionCharts V3图表导出图片和PDF属性说明
2012-10-20 17:29 790http://www.cnblogs.com/ATree/ar ... -
FusionCharts的中文乱码问题
2012-10-20 17:20 673原文地址:http://wangyaobeijing.b ... -
12 个有效的提高编程技能的方法
2012-10-14 19:17 529来源于:http://www.oschina.net/news ... -
JAVA MVC框架性能比较
2012-09-09 17:28 742来源:http://www.blogjava.net/p ... -
低级别工具 —— 锁定和原子
2012-09-09 17:26 749Lock Java 语言内置了锁定工具 —— sync ... -
Synchronizer 类
2012-09-09 17:26 707Synchronizer 类 Synchroni ...
相关推荐
在C#中,实现`ISerializable`接口的示例通常涉及创建一个私有的构造函数来处理反序列化,并在`GetObjectData`方法中明确指定要序列化的字段。这在需要特殊处理的复杂对象或敏感数据时特别有用。 总之,序列化是.NET...
### 序列化与持久化的相同点与不同点 #### 一、持久化定义与应用场景 **持久化**是指将程序中的数据(如内存中的对象)保存到可长期存储的设备上,比如硬盘或者固态硬盘等。持久化的主要目的是确保即使在程序结束...
通过使用`transient`关键字、自定义序列化方法或第三方库,我们可以排除对象中不希望被序列化的属性。理解这些机制对于编写安全且高效的Java应用程序至关重要。 在学习过程中,阅读相关的文档和博客,例如提供的...
在Java中,我们可以使用`ObjectInputStream`类的`readObject()`方法来完成这个操作。在学生管理系统中,当程序启动时,它会读取之前保存的字节流,通过反序列化将学生对象重新构建,这样就可以继续管理和显示学生...
而在Java中,我们可以通过实现`Serializable`接口来使类支持序列化,或者使用`java.io.ObjectOutputStream`和`java.io.ObjectInputStream`进行对象的序列化和反序列化。 接下来,我们讨论反序列化。反序列化是序列...
- 序列化通常只对公共字段和属性生效,私有成员默认不会被序列化。 - 可以通过添加 `[Serializable]` 特性标记一个类为可序列化的。 - 对于不想序列化的字段,可以使用 `[NonSerialized]` 特性。 - 对于.NET Core,...
需要注意的是,实现序列化的类应该谨慎处理其内部状态,因为序列化会保存对象的所有字段,包括私有(private)和受保护的(protected)成员。如果某个类的父类没有实现`Serializable`接口,那么子类仍然可以序列化,...
这个类可能包含了一些方法,如`Serialize`(将对象序列化为XML字符串或写入XML文件)和`Deserialize`(从XML字符串或文件反序列化回对象)。 接下来,`说明.txt`文件应该提供了关于如何使用这个项目的详细指南。它...
如果存储的对象由你自己创建,你可以通过在类定义前添加`[Serializable]`属性来使其可序列化。例如: ```csharp [Serializable] public class ParmXRLV { public double A { get; set; } public double S { get; ...
.NET对象序列化与数据持久化.NET对象序列化与数据持久化.NET对象序列化与数据持久化.NET对象序列化与数据持久化.NET对象序列化与数据持久化.NET对象序列化与数据持久化(Q群号:152088818 本群只为有经验的.NET开发者...
在IT行业中,序列化和反序列化是两个关键的概念,特别是在对象持久化、数据传输以及存储方面。在Delphi编程环境中,这两个概念同样至关重要。本文将深入探讨Delphi中的序列化与反序列化,以及如何处理组件和结构体的...
返回的是一个包含需要序列化属性名的数组。 ```php class MyClass { private $var1; private $var2; public function __sleep() { // 只序列化$var1 return ['var1']; } } ``` - `__wakeup()`:在反序列化...
这对于优化自定义序列化逻辑或者解决Hessian使用中遇到的问题非常有帮助。 总结起来,Hessian是一种高效、轻量级的二进制序列化协议,特别适合于跨语言的网络通信。理解并掌握Hessian的基本概念和使用方法,能够...
序列化与反序列化是计算机科学中的重要概念,特别是在数据存储、网络通信和持久化对象等领域。简单来说,序列化是将对象的状态转换为可存储或传输的数据格式的过程,而反序列化则是将这种数据格式恢复为原来的对象...
1. 只有公共属性和字段会被序列化,私有和受保护的成员不会被包含。 2. 对于依赖关系和循环引用的对象,需要特殊处理。 3. 序列化可能导致安全问题,因此应谨慎处理敏感数据。 总结,C#序列化是开发过程中不可或缺...
1. 复杂类型的处理:除了基本类型外,还可以序列化和反序列化自定义类、结构体以及容器(如vector、map等)。对于自定义类型,通常需要重载`operator和`operator>>`,或者使用nlohmann/json库中的`to_json`和`from_...
1. **序列化类**:这个类可能有一个方法,如`Serialize(T obj, string filePath)`,用于接收一个对象和目标文件路径,然后将对象序列化并保存到文件中。它可能会使用Stream或StreamWriter来写入数据,并可能支持多种...
总结来说,这个程序利用C#的类序列化技术,提供了一种有效的方法来存储和恢复大量数据,同时优化了文件拷贝和大规模数据管理。通过理解和应用这些知识点,开发者可以创建更灵活、高效的应用程序,特别是在处理数据...
在本篇文章中,我们将会讲解如何使用 Unity 序列化和反序列 XML,并添加属性来实现游戏中的数据存储和读取。 一、Unity 序列化 Unity 序列化是指将游戏中的数据转换为 XML 格式的字符串,以便存储到文件中。 在 ...
Java序列化是Java平台中的一种持久化机制,它允许对象的状态被转换成字节流,以便存储、网络传输或在不同时间点恢复。这个过程被称为序列化,而反向操作称为反序列化。序列化在许多场景下都非常有用,比如在分布式...