讨论一下, 这样会不会造成大量的垃圾?

08-02-14 alexlee002
我在设计一个sp短信网关, 关于业务分发/计费这块,有些问题想请教一下:

目前系统把每个业务配置都封装成一个对象(ServiceInfo), 系统启动的时候, 把这些对象都加载到hashtable中。
用户每条上行信息都封装成一个Message对象, 这里边有一个serviceInfo属性,用来存储每条信息匹配到的业务配置。
这样有个问题, 原先的系统中, message对象中的serviceinfo属性赋值是直接从hashtable中get出serviceInfo, 大家直到, java的对象是引用机制, 这样, 如果在某个地方修改了message的serviceinfo, 那么hashtable里边相应的信息也被修改, 这样是不允许的,
如果使用clone, 不直接把hashtable里的对象赋给message, 而是clone一份再赋值, 这样能避免上面的问题, 但是也引发出一个问题:产生大量的对象, 用户上行的短信很多, 或者正在做群发, 这样会不会造成系统性能下降?

alexlee002
2008-02-15 15:54
彭老大帮我看看?

banq
2008-02-15 18:01
首先产生大量对象与性能下降没有直接因果关系。

原型模式不一定使用clone实现,使用Jdk本身的clone可能性能比较低,可以在serviceinfo构造方法中,加入 Serviceinfo serviceinfo = new Serviceinfo();然后将原来的serviceinfo 手工转移拷贝到新的serviceinfo 中。

如果出现性能问题,可能需要考虑集群,比如采取JMS或将负载大的计算Bean使用其他服务器来执行。

johnnylzb
2008-02-21 17:24
尝试从技术的角度回到你的问题,不知道能否对你有帮助。

按照你描述的场景,依我的推断,这个“业务配置”(ServiceInfo)应该是系统初始化之后就不能改动的一个全局变量,也就是一个系统常量吧。

对于系统常量,当然不能供外界随便修改,这可能会出现安全漏洞,甚至导致系统崩溃。

而你的解决方案,正如你自己的分析,通过“拷贝”对象保持原有对象的“非可变性”,这从技术的角度是合理的设计,这叫“保护性拷贝”,但这样就出现了对象数量大大增加,浪费内存的后果。可以说,“保护性拷贝”是某种场合下的合理和安全的设计,但并不适合你的应用场景。因为你的ServiceInfo是全局性的,不应该让每个线程拥有一份。

面对这样的场景,不能使用数组或者HashTable去保存你的系统信息常量,因为数组和可变的Collection都无法保证其不可变性(参考《Effective Java》)

所以,只能以常量去定义你的多个ServiceInfo,代码示例如下:

public class ServcieInfo {
private String member1;
private String member2;

public static final SYSTEM_SERVICE_INFO_1; //业务配置1

public static final SYSTEM_SERVICE_INFO_2; //业务配置2

...

public static final SYSTEM_SERVICE_INFO_N; //业务配置N

static {
// 如果你的业务配置需要从外部设置(例如从Properties文件或XML文件),则在这个静态块里面完成SYSTEM_SERVICE_INFO_N的实例化
}

public String getMember1() {
return member1;
}

public String getMember2() {
return member2;
}

private void setMember1(String member1) {
this.member1=member1;
}

private void setMember2(String member2) {
this.member2=member2;
}

private ServiceInfo(String member1,String member2) {
this.member1=member1;
this.member2=member2;
}
}

说明:
1.不允许外界对ServiceInfo的成员变量作任何修改,因此成员变量需要定义为private,并且不提供public的setter方法
2.让ServiceInfo的构造函数私有化,从而保证了外界无法轻易“伪造”(为什么是“轻易”,因为外界还是可以通过反射机制“伪造”)
3.让各个ServiceInfo声明为public static final常量,外界无法修改它的“引用”(Reference)
4.这里只对ServiceInfo的定义进行了示例,如果你的ServiceInfo有其他类型的成员变量(比如自定义类型),千万千万要记住,把这些成员变量设计为“非可变对象”(Immutable Object)

这样,外界只能通过 ServiceInfo.SYSTEM_SERVICE_INFO_N使用你的业务配置信息,他们没法修改你的业务配置信息,也无法创建,同时无法改变你的常量的引用,即使外界通过getter方法获得了ServiceInfo的成员变量的实例并进行“恶意”修改,由于你的成员变量是“非可变“的,他们的修改也不会影响你的全局业务配置

[该贴被johnnylzb于2008-02-21 17:25修改过]

[该贴被johnnylzb于2008-02-21 17:27修改过]

ghostv1
2008-03-13 16:36
应该这样,这样所有修改只在一个地方,比较容易控制

猜你喜欢