队列框架方案之消息通知解决方案

 

队列框架方案之消息通知解决方案

项目实施规范

编号:DEMO-NOTIFY-PROJ

版本:1.0

 

 

 

作者

YINGUANG

日期

2009-03-25

             

 

 

 

1概述

在进行系统设计时,除了对安全、事务等问题给与足够的重视外,性能也是一个不可避免的问题所在,尤其是一个B/S结构的软件系统,必须充分地考虑访问量、数据流量、服务器负荷的问题。解决性能的瓶颈,除了对硬件系统进行升级外,软件设计的合理性尤为重要。对于一些实时性不是很高的模块我们可以使用了Microsoft Messaging Queue(MSMQ)技术来完成异步处理,利用消息队列临时存放要操作的数据,使得数据访问因为不需要访问数据库从而提高了访问性能,至于队列中的数据,则等待系统空闲的时候再进行处理。【摘自张逸】

消息通知系统就是利用MSMQ技术、window服务实现一系列的通知服务。

1.1    目的

n         为消息通知提供解决方案

 

n         本文档的编写也为下阶段的设计、开发提供依据,为项目组成员对需求的详尽理解,以及在开发开发过程中的协同工作提供强有力的保证。同时本文档也作为项目评审验收的依据之一。

1.2    范围

消息通知解决方案中包括 消息的发送、接受模块;消息的处理模块;消息通知模块等三大模块。

1.3    参考资料

l         C#高级编程 Wrox[消息队列,window服务]

l         PetShop数据访问层之消息处理

l         敏捷软件开发

l         重构-改善既有代码的设计

l         HeadFirst设计模式

1.4    术语定义

用户:是指技术部人员而非客户或软件的最终购买者。

消息:是由通信的双方所需要传递的信息,它可以是各式各样的媒体,如文本、声音、图象等等。我们这里仅仅指MSMQMessage

消息体:指专门自己定义的一个超类MessageBase。自定义消息体这样做的好处是,一是相当于对数据进行了简单的加密,二则采用自己定义的格式可以节省通信的传递量

 

namespace DEMO.Notify.Server

{

    [Serializable]

    public class MessageBase

    {

        /// <summary>

        /// 消息类型

        /// </summary>

        private string messagetype;

        public string MessageType

        {

            get { return messagetype; }

            set { messagetype = value; }

        }

        /// <summary>

        /// 消息内容

        /// </summary>

        private string messagebody;

        public string MessageBody

        {

            get { return messagebody; }

            set { messagebody = value; }

        }

    }

}

 

1.5    概述

 

用户利用本系统提供的接口向消息队列发送消息。Window服务通过轮询监视消息队列的数据,并取出消息,根据消息类型通过工厂创建具体的消息处理器Processor处理消息,然后把消息通过消息投递器Poster发送指定的买家、卖家、客服等。

 

 

 

 

 

2       UML

2.1          Sequence Diagram

2.2          class Diagram

 

3       接口设计

3.1    消息体MessageBase重构

3.1.1   重构过程

自定义消息体的好处很多,比如采用自己定义的格式相当于对数据进行了简单的加密,采用自己定义的格式可以节省通信的传递量等等。

因为我们的系统是为处理订单通知服务的,所以消息体的大概内容应该是订单的类型[订单生成、订单支付成功等],消息内容更确切的讲应为构造发送内容必须的参数[目前一个OrderId就够了]

其消息体的代码如下:

   [Serializable]

    public class MessageBase

    {

       /// <summary>

        /// 消息类型

        /// </summary>

        private string messagetype;

        public string MessageType

        {

            get { return messagetype; }

            set { messagetype = value; }

        }

        /// <summary>

        /// 消息内容

        /// </summary>

        private string messagebody;

        public string MessageBody

        {

            get { return messagebody; }

            set { messagebody = value; }

        }

    }

说明:1:消息体必须可序列化也就是有Serializable特性

      2:消息体尽量为轻量级内容

3.1.2   UML

 

3.2    客户端组件重构.

3.2.1   重构过程

这个和PetShop的消息发送、接收是一样滴,就不多说了。

 

3.2.2   UML

 

3.3    Section节点重构

3.3.1   重构过程

先看看app.config里的一段Section代码

Code

 

 

上面的Section节点是该系统的纽带!没有它,系统将无法运行,发送器、处理器也成了独立的羔羊。既然很重要,那我们也就重点说说这个流程吧。

l         Notify继承 System.Configuration.ConfigurationSection它里面有ConnectionStringsClientMailsMessageTypesMessageProcessorsMessageSendersConfigurationProperty

l         ConnectionStrings继承ConfigurationElementCollection它保存了不同数据源的 connectionstring.

l         ClientMails继承 ConfigurationElementCollection, 它保存了常用的客服email

l         MessageSenders 是个ConfigurationElement , 里面配置Poster需要的信息。比如MailSender保存了Emaildomain,userid,pwd,from等相关信息。

l         MessageProcessor 是个ConfigurationElementCollection, 里面的每个ConfigurationElement保存了每个处理器和对应的Asssembly这样就可以通过下面的代码创建对应的处理器。

Type type = Type.GetType(processName);

Assembly a = Assembly.GetAssembly(type);

Object obj = a.CreateInstance(processName);

return obj as IProcessor;

l         MessageTypes 保存了每个消息类型[OrderCreate,OrderPaySucceed] 的个性特征。我们的系统就是通过MessageTypes里的每个MessageTypeProcessorMessageProcessor找对应的处理器的。

        1name:它就是消息体MessageBaseMessageType属性,当系统从msmq里取到消息后,就会根据nameMessageTypes找和MessageType匹配对应的条目

      2: processor 当从MessageTypes里找到对应的条目后,就会通过processorMessageProcessor去找对应的处理器。

      3Poster:它是对应了每个Messagetype[一个MessageType对应一个MessageProcessor]所需要的发送器Poster。多个Poster用逗号隔开。这样我们就可以配置发送器了。

      3Parameter:是增加的特性列表。其中Consumer,merchant,Client对应了买家、卖家、客服的内容模板,

guestEmail对应客户的email

3.3.2   UML

....

.

3.4    发送器Poster的重构

3.4.1   重构过程

商城的订单状态行为会产生通知,通知的方式目前有Email,sys,IM,他们三个有个共同的方法那就是Post投递方法,我们可以把Email,sys,IM当成三个Poster类,并且都有Post的方法。 代码如下:

public class EmailPoster

{

    public void Post(param1)

    {

        //TODO:Process order and Post

    }

}

public class IMPoster

{

    public void Post(param2)

    {

        //TODO:Process order and post

    }

}

public class syslogPoster

{

    public void Post(param3)

    {

        //TODO:Process order and post

    }

}

我们细看上面的代码,按照一般的重构常理应该提出一个基类或接口了。这里用接口更合适些,抽取出来的接口如下:

public interface ImsgPoster

{

        void post(SenderInfo sender);

    }

备注:SenderInfo是一个超类,用来保存要格式化内容时需要的参数

最后完整的代码如下:

public class EmailPoster : ImsgPoster

{

    public void Post(SenderInfo sender)

   {

        //TODO:Process order

    }

}

public class IMPoster : ImsgPoster

{

    public void Post(SenderInfo sender)

    {

        //TODO:Process order

    }

}

public class syslogPoster : ImsgPoster

{

    public void Post(SenderInfo sender)

    {

        //TODO:Process order

    }

}

 public interface ImsgPoster

    {

        void Post(SenderInfo sender);

    }

 

public class SenderInfo

{}

3.4.2   UML

 

3.5    处理器重构

3.5.1   重构过程

假设我们把处理每个订单状态[订单生成、订单支付]的程序叫处理器Processor,每个订单状态都有个处理器,比如订单生成、订单支付对应的处理器为OrderCreateProcessor, OrderPaySucceedProcessor,每个处理器都有Process方法,该方法用来生成买家、卖家、客服等发送对象的内容,并调用Process把通知投递出去。通过上述讨论,代码大概如下:

public class OrderCreateMsgProcessor

{

    public void Process()

    {

        //TODO:Poster

    }

    private SenderInfo ConsumerEditor()

    {

        //TODO:构造买家SenderInfo

    }

    private SenderInfo MerchantEditor()

    {

        //TODO:构造卖家SenderInfo

    }

    private SenderInfo ClientEditor()

    {

        //TODO:构造客服SenderInfo

    }

 

}

OrderPaySucceedProcessor.cs的代码内容和上述代码没有什么区别。我们也应该抽象出一个基类或者接口。因为这里是’is a’的关系,而并非’behave like’的关系,并且抽象出来的目的是为了有共有的功能,而非约定、合同。所以我们选择了抽象类。该抽象类UML图如下:

IProcessor 抽象类有4个属性 ClientTemplate,MerchantTemplate,ConsumerTemplate代表了客服、商家、买家的内容模板,MsgMessage类型,它保存了从消息队列取的消息条目信息;AddPoster方法向发送器列表里添加了一个发送器,AddSender向发送对象列表里添加了一个SenderInfo[这个SenderInfo是派生类中ConsumerEditor, MerchantEditor, ClientEditor方法构造出来的.],IntialProcessor用来初始化处理器ProcessorIProcessor完整的代码如下:

public abstract class IProcessor

{

    private System.Messaging.Message msg;

    #region templates variables

    //Processor通过模板生成不同发送对象的内容

    private string _consumertemplate;//买家模板

    private string _merchanttemplate;//卖家模板

    private string _clienttemplate;//客服模板

    #endregion

    private List<SenderInfo> senderlist = new List<SenderInfo>();//发送对象列表

    private List<ImsgPoster> posterlist = new List<ImsgPoster>();//发送器列表

    #region template properties

    public string ClientTemplate

    {

        get { return _clienttemplate; }

        set { _clienttemplate = value; }

    }

    public string MerchantTemplate

    {

        get { return _merchanttemplate; }

        set { _merchanttemplate = value; }

    }

    public string ConsumerTemplate

    {

        get { return _consumertemplate; }

        set { _consumertemplate = value; }

    }

    #endregion

 

    /// <summary>

    /// 初始化Poster[发送器]Template[模板文件]

    /// </summary>

    protected void InitialProcessor()

    {

        NotifySection section = (NotifySection)System.Configuration.ConfigurationManager.GetSection("Notify");

        //获取消息类型

        string msgType = String.Empty;

        msgType = ((MessageBase)msg.Body).MessageType.ToString();

        //获取发送器列表,以逗号隔开!

        string poster = section.MsgTypes[msgType].Poster.ToString();

        string[] posters = poster.Split(new char[] { ',' });

        foreach (string pst in posters)

        {

            AddPoster(DataAccess.CreateMsgPoster(pst));

        }

        _merchanttemplate = section.MsgTypes[msgType].Parameters["Merchant"].ParamValue.ToString();

        _consumertemplate = section.MsgTypes[msgType].Parameters["Consumer"].ParamValue.ToString();

        _clienttemplate = section.MsgTypes[msgType].Parameters["Client"].ParamValue.ToString();

 

    }

    /// <summary>

    /// 消息

    /// </summary>

    public System.Messaging.Message Msg

    {

        get { return msg; }

        set { msg = value; }

    }

    /// <summary>

    /// 添加SenderInfo(发送对象)

    /// </summary>

    /// <param name="sender">发送对象</param>

    protected void AddSender(SenderInfo sender)

    {

        senderlist.Add(sender);

    }

 

    /// <summary>

    /// 添加发送器

    /// </summary>

    /// <param name="poster">发送器:Email,Msn,Qq,Yahoo,Sms</param>

    public void AddPoster(ImsgPoster poster)

    {

        posterlist.Add(poster);

    }

 

    /// <summary>

    /// 这个是最关键的地方,用virutal实现多态,从而减少发送器和发送对象的耦合性!~..~

    /// </summary>

    public virtual void Process()

    {

        if (senderlist != null)

        {

            for (int i = 0; i < senderlist.Count; i++)

            {

                //senderlist[i];

                foreach (ImsgPoster poster in posterlist)

                {

                    poster.post(senderlist[i]);

                }

            }

        }

    }

 

}

现在OrderCreateMsgProcessor类代码如下:

public class OrderCreateMsgProcessor : IProcessor

{

    private SenderInfo ECConsumerEditor()

    {   }

    private SenderInfo MerchantEditor()

    {   }

    private SenderInfo ClientEditor()

    {}

    /// <summary>

    /// 实现父类的Process 方法。

    /// </summary>

    public override void Process()

    {

        //initial processor

        base.InitialProcessor();

       

        //添加买家到链表中~。。~

        SenderInfo sender;

        sender = ECConsumerEditor();

        if (sender != null)

        {

            base.AddSender(sender);

        }

        //添加商家到链表中·。。

        sender = MerchantEditor();

        if (sender != null)

        {

            base.AddSender(sender);

        }

        //添加客服到链表中~。。~

        sender = ClientEditor();

        if (sender != null)

        {

            base.AddSender(sender);

        }

        //邮递员发送到各个地方!

        base.Process();

    }

 

}

IProcessorInitialProcessor里有个NotifySection对象,这个对象将在3.3的配置节点重构章节里说明。

3.5.2   UML

 

 

 

4       实例演示下载

demo.notify.rar

posted @ 2009-04-27 14:24  roboth  阅读(3437)  评论(10编辑  收藏  举报