在JEE软件开发中,通常会对系统模块进行分层。展示层主要负责数据的展示,定义数据库的UI组织模式;业务逻辑层负责具体的业务逻辑处理;持久层通常指数据库以及相关操作。在一个大型系统中,这些层次有可能被分离,并部署在不同的服务器上,则在两个层次之间,可能通过远程过程调用RMI等方式进行通信。假设订单由客户名、商品名、数量构成。则获取这些信息的客户端可能和服务端进行三次交互,来依次获得这些信息。
基于以上模式的通信方式是一个可行的解决方案,但是存在两个严重的问题:对于获取一个订单对象而言,这个操作模式略显繁琐,且不具备较好的可维护性;前后累计进行了多次客户端与服务器端的通信,性能成本较高。为了解决这个问题,可以是Value Object模式。Value Object模式提倡将一个对象的各个属性进行封装,将封装后的对象在网络中传递,从而使系统具有更好的交互模型,并且减少网络通信数据,从而提高系统性能。使用Value Object模式对以上结构进行改良,定义Order对象,由Order对象维护订单的信息,而且Order对象必须是可系列化的对象。
使用Value Object模式可以有效减少网络交互次数,提高远程调用方法的性能,也是系统接口具有更好的可维护性。
RMI服务端接口:
package com.performance.optimization.design.valueobject;
import java.rmi.Remote;
import java.rmi.RemoteException;
/**
* RMI 服务端接口
* @author qiaolin
*
*/
public interface IOrderManager extends Remote{
Order getOrder(int id) throws RemoteException;
String getClientName(int id) throws RemoteException;
String getProductName(int id) throws RemoteException;
int getNumber(int id) throws RemoteException;
}
RMI服务端接口实现,主要是获取数据:
package com.performance.optimization.design.valueobject;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
/**
* 订单接口的实现类
* @author qiaolin
*
*/
public class OrderManager extends UnicastRemoteObject implements IOrderManager{
protected OrderManager() throws RemoteException {
super();
}
private static final long serialVersionUID = 1L;
public Order getOrder(int id) throws RemoteException {
Order order = new Order();
order.setClientName("Client Name");
order.setNumber(10);
order.setProductName("Product Name");
return order;
}
public String getClientName(int id) throws RemoteException {
return "Client Name";
}
public String getProductName(int id) throws RemoteException {
return "Product Name";
}
public int getNumber(int id) throws RemoteException {
return 10;
}
}
ValueObject的订单实体类:
package com.performance.optimization.design.valueobject;
import java.io.Serializable;
/**
* value object 订单类 可串行化
* @author qiaolin
*
*/
public class Order implements Serializable{
private static final long serialVersionUID = 6685112428371713948L;
private int orderId;
private String clientName;
private int number;
private String productName ;
public int getOrderId() {
return orderId;
}
public void setOrderId(int orderId) {
this.orderId = orderId;
}
public String getClientName() {
return clientName;
}
public void setClientName(String clientName) {
this.clientName = clientName;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
}
调用测试,本例使用Junit测试,调用测试之前,首先需要对服务端接口进行注册和绑定:
package com.performance.optimization.design.valueobject;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import org.junit.Before;
import org.junit.Test;
public class ValueObjectTest {
@Before
public void before(){
try {
//注册端口 8081
LocateRegistry.createRegistry(1099);
IOrderManager orderManager = new OrderManager();
//把指定名称重新绑定到一个新的远程对象
Naming.rebind("OrderManager", orderManager);
System.out.println("OrderManager is ready.");
} catch (RemoteException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
@Test
public void test(){
try {
//获取远程对象
IOrderManager orderManager = (IOrderManager) Naming.lookup("rmi://localhost:1099/OrderManager");
int cycle = 1000;
long begin = System.currentTimeMillis();
for(int i = 0; i<cycle;i++){
orderManager.getOrder(i);
}
System.out.println("Value Object Spend:" + (System.currentTimeMillis() - begin));
begin = System.currentTimeMillis();
for(int i = 0; i<cycle;i++){
orderManager.getClientName(i);
orderManager.getProductName(i);
orderManager.getNumber(i);
}
System.out.println("Method called Spend:" + (System.currentTimeMillis() - begin));
System.out.println(orderManager.getOrder(0).getClientName());
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (RemoteException e) {
e.printStackTrace();
} catch (NotBoundException e) {
e.printStackTrace();
}
}
}
测试结果分析,当循环次数为1000时,花费时间是valueObject模式的代价较大。当循环次数超多1000时,valueObject模式花费的代价远比三次调用小。
当循环次数为1000时
OrderManager is ready.
Value Object Spend:273
Method called Spend:256
Client Name
当循环次数为100000时
OrderManager is ready.
Value Object Spend:8660
Method called Spend:17036
Client Name