《解剖PetShop》之三:PetShop数据访问层之消息处理

三、PetShop数据访问层之消息处理

  在进行系统设计时,除了对安全、事务等问题给与足够的重视外,性能也是一个不可避免的问题所在,尤其是一个B/S结构的软件系统,必须充分地考虑访问量、数据流量、服务器负荷的问题。解决性能的瓶颈,除了对硬件系统进行升级外,软件设计的合理性尤为重要。

  在前面我曾提到,分层式结构设计可能会在一定程度上影响数据访问的性能,然而与它给设计人员带来的好处相比,几乎可以忽略。要提供整个系统的性能,还可以从数据库的优化着手,例如连接池的使用、建立索引、优化查询策略等等,例如在PetShop中就利用了数据库的Cache,对于数据量较大的订单数据,则利用分库的方式为其单独建立了Order和Inventory数据库。而在软件设计上,比较有用的方式是利用多线程与异步处理方式。

  在PetShop4.0中,使用了Microsoft Messaging Queue(MSMQ)技术来完成异步处理,利用消息队列临时存放要插入的数据,使得数据访问因为不需要访问数据库从而提供了访问性能,至于队列中的数据,则等待系统空闲的时候再进行处理,将其最终插入到数据库中。

  PetShop4.0中的消息处理,主要分为如下几部分:消息接口IMessaging、消息工厂MessagingFactory、MSMQ实现MSMQMessaging以及数据后台处理应用程序OrderProcessor。

  从模块化分上,PetShop自始自终地履行了“面向接口设计”的原则,将消息处理的接口与实现分开,并通过工厂模式封装消息实现对象的创建,以达到松散耦合的目的。

  由于在PetShop中仅对订单的处理使用了异步处理方式,因此在消息接口IMessaging中,仅定义了一个IOrder接口,其类图如下:

/uploads/allimg/200612/1F94I961_0.gif


  在对消息接口的实现中,考虑到未来的扩展中会有其他的数据对象会使用MSMQ,因此定义了一个Queue的基类,实现消息Receive和Send的基本操作:

public virtual object Receive() { try { using (Message message = queue.Receive(timeout, transactionType)) return message; } catch (MessageQueueException mqex) { if (mqex.MessageQueueErrorCode == MessageQueueErrorCode.IOTimeout) throw new TimeoutException(); throw; } } public virtual void Send(object msg) { queue.Send(msg, transactionType); }

  其中queue对象是System.Messaging.MessageQueue类型,作为存放数据的队列。MSMQ队列是一个可持久的队列,因此不必担心用户不间断地下订单会导致订单数据的丢失。在PetShopQueue设置了timeout值,OrderProcessor会根据timeout值定期扫描队列中的订单数据。

  MSMQMessaging模块中,Order对象实现了IMessaging模块中定义的接口IOrder,同时它还继承了基类PetShopQueue,其定义如下:

public class Order:PetShopQueue, PetShop.IMessaging.IOrder   方法的实现代码如下: public new OrderInfo Receive() { // This method involves in distributed transaction and need Automatic Transaction type base.transactionType = MessageQueueTransactionType.Automatic; return (OrderInfo)((Message)base.Receive()).Body; } public OrderInfo Receive(int timeout) { base.timeout = TimeSpan.FromSeconds(Convert.ToDouble(timeout)); return Receive(); } public void Send(OrderInfo orderMessage) { // This method does not involve in distributed transaction and optimizes performance using Single type base.transactionType = MessageQueueTransactionType.Single; base.Send(orderMessage); }

所以,最后的类图应该如下:

/uploads/allimg/200612/1F94912W_0.gif

注意在Order类的Receive()方法中,是用new关键字而不是override关键字来重写其父类PetShopQueue的Receive()虚方法。因此,如果是实例化如下的对象,将会调用PetShopQueue的Receive()方法,而不是子类Order的Receive()方法:

PetShopQueue queue = new Order(); queue.Receive();

从设计上来看,由于PetShop采用“面向接口设计”的原则,如果我们要创建Order对象,应该采用如下的方式:

IOrder order = new Order(); order.Receive();

考虑到IOrder的实现有可能的变化,PetShop仍然利用了工厂模式,将IOrder对象的创建用专门的工厂模块进行了封装:

/uploads/allimg/200612/1F94GE8_0.gif

在类QueueAccess中,通过CreateOrder()方法利用反射技术创建正确的IOrder类型对象:

public static PetShop.IMessaging.IOrder CreateOrder() { string className = path + ".Order"; return PetShop.IMessaging.IOrder)Assembly.Load(path).CreateInstance(className); }

path的值通过配置文件获取:

private static readonly string path = ConfigurationManager.AppSettings["OrderMessaging"];

而配置文件中,OrderMessaging的值设置如下:

<add key="OrderMessaging" value="PetShop.MSMQMessaging"/>

之所以利用工厂模式来负责对象的创建,是便于在业务层中对其调用,例如在BLL模块中OrderAsynchronous类:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wjypyg.html