统一对象消息编程(4)—对象消息编程框架3(基本模块类TLBaseModule)

     在前几章的基础上,我们开始介绍最重要的消息对象类模块TLBaseModule。TLBaseModule继承TLBaseObject。TLBaseModule可以说是个软件实现的CPU了,消息就是指令,它可以对指令检测、分析、执行、转发。从前面介绍的类关系图中看到TLBaseModule是最重要的类,所有其他的实用模块都继承它。对象消息编程框架基本就是这个类模板。

一、主要属性

      1、protected ArrayList<TLMsg> initMsgTable  

          存储消息表。在对象初始化的时候自动执行表中的消息。

      2、protected HashMap<String, ArrayList<TLMsg>> msgTable; 

         消息路由表 。Map格式:消息ID—》消息。

       对于接收的消息,如果设置了消息ID,则在表中取出对应的消息而执行,一个消息ID可以对应多个消息,因此可以执行多个消息链。

     3、protected HashMap<String, ArrayList<TLMsg>> beforeMsgTable

     消息前期处理表。Map格式:action-》消息链list

    对于接收到的消息,如果没有设置消息ID,则分析消息action,在执行action之前,执行beforeMsgTable里面的action对应的消息链。

    4、protected HashMap<String, ArrayList<TLMsg>> afterMsgTable;

    消息后期处理表。Map格式:action-》消息链list

   在执行action之后,执行afterMsgTable表里面的action对应的消息链。

   5、 protected Map<String, Object> modules   

    模块对象表   。格式:模块名-》模块实例

    为了不用每次从工厂取出模块,对于使用过的模块可存在模块对象表里,提高效率。编程时一般不用考虑。

   6、protected HashMap<String, String> params;  

    参数存储表。xml配置文件中的param项目自动存到该属性中,根据情况可设置。

   7、protected TLObjectFactory moduleFactory  

      模块工厂实例。每次应用某个模块对象时,从模块工厂中获得,模块工厂负责模块的创建、配置。

二、主要方法

1、启动、配置

public void start(String configFile ,HashMap<String, String> params){
    if(configFile !=null)
        this.configFile=configFile;
    if(params !=null)
        this.params=params;
    setConfig();
    initProperty();
    init();
    runInitMsg();
}

该方法一般由模块工厂调用,模块工厂创建一个模块对象后,自动执行该方法,完成模块配置、属性设置、运行初始消息表。

2 处理消息

   在TLBaseObject类中,我们实现了基本接口IObject的putMsg方法,在TLBaseModule模块中,主要实现了getMsg方法。getMsg主要完成通用的消息分析、转发、前后期消息处理及一般系统级别的通用方法。

public TLMsg getMsg(Object fromWho, TLMsg msg) {
    msg=preGetMsg(fromWho,msg);
    TLMsg returnMsg=mget( fromWho,  msg);
    return afterGetMsg(fromWho,msg,returnMsg);
}

protected TLMsg mget(Object fromWho, TLMsg msg){
    TLMsg returnMsg ;
    String destination = msg.getDestination();
    if (destination != null &&  !destination.equals(name))
    {
        TLMsg tranferMsg=createMsg().setAction("msgTransfer").setParam("msg",msg);
        msg=tranferMsg;
    }
    String msgId = msg.getMsgId();
    if (msgId == null || msgId.isEmpty())  //检查是否设置msgid
    {
        returnMsg = doBeforAndAfterMsgTable("before", msg,null);
        if (!ifDoNextMsg((TLMsg) returnMsg.getParam(MINFO_PRERESULT)))
            return (TLMsg) returnMsg.getParam(MINFO_PRERESULT);
        returnMsg=  runAction(fromWho, returnMsg);
        returnMsg=doBeforAndAfterMsgTable("after", msg,returnMsg);
    } else
        returnMsg = checkMsgId(msgId, fromWho, msg);
    if (!ifDoNextMsg(returnMsg)) return returnMsg;
    TLMsg nextMsg = msg.getNextMsg(); //取出param中下一个消息
    if (nextMsg != null )
        return putMsg(this, nextMsg);
    else
        return returnMsg;
}

preGetMsg(fromWho,msg) 、afterGetMsg(fromWho,msg,returnMsg)为空方法,如果需要公共的消息前后期处理,可覆盖该方法,如果没有需求,则不用考虑。主要方法为mget( fromWho, msg) 。消息处理流程如下图:

mget方法中过程如下;

首先对消息目的检测,如果目的不是本模块,则转出到对应目的模块。

如果消息设置了消息ID,则转到消息id处理,根据ID在消息路由表 msgTable中取出消息ID对应的消息进行处理、运行。一个消息ID可以对应多条消息。

如果没有设置消息id,则分析消息中的action。根据action执行 消息前期处理表beforeMsgTable。beforeMsgTable中一个action可以对应多条消息。

消息前期处理表运行完毕后,如果结果允许继续运行,则执行分析action的方法runAction(fromWho, returnMsg);

protected TLMsg runAction(Object fromWho, TLMsg msg){
    TLMsg returnMsg=  systemMsgs(fromWho, msg);
    if(returnMsg ==null)
        returnMsg = checkMsgAction(fromWho, msg);
   return returnMsg;
}

在runAction(fromWho, returnMsg)方法中,首先执行系统定义的通用方法,如消息路由表动态设置、初始化等。

protected TLMsg systemMsgs(Object fromWho, TLMsg msg) {
    String action =msg.getAction();
    if (action==null)
        action="";
    TLMsg returnMsg ;
    switch (action) {
        case SETFACTORY:
            moduleFactory= (TLObjectFactory) msg.getParam("moduleFactory");
            returnMsg=msg;
            break;
        case INITACTION:
            init();
            runInitMsg();
            returnMsg=msg;
            break;
        case INJECTMODULE:
            injectModule(msg);
            returnMsg=msg;
            break;
        case ADDMSGTABLE:
            if (msgTable == null)
                msgTable = new HashMap<>();
            addMsgTable(msgTable, "msgId", msg);
            returnMsg=msg;
            break;
        case ADDINITMSG:
            addInitMsg(msg);
            returnMsg=msg;
            break;
        case ADDBEFOREMSG:
            if (beforeMsgTable == null)
                beforeMsgTable = new HashMap<>();
            addMsgTable(beforeMsgTable, "action", msg);
            returnMsg=msg;
            break;
        case ADDAFTERMSG:
            if (afterMsgTable == null)
                afterMsgTable = new HashMap<>();
            addMsgTable(afterMsgTable, "action", msg);
            returnMsg=msg;
            break;
        case RELOADCONFIG:
            setConfig();
            initProperty();
            putLog(name+" 配置重新加载",LogLevel.INFO);
            returnMsg=msg;
            break;
        case"msgTransfer":
            returnMsg=msgTransfer( fromWho, msg);
            if(returnMsg==null)
               returnMsg=msg;
            break;
        case "destroy":
            destroy( fromWho, msg);
            returnMsg=msg;
            break;
        default:
            returnMsg=null;
    }
    return returnMsg ;
}

如果action不属于系统action,则执行用户定义的action。在方法中checkMsgAction(fromWho, msg)中执行用户自定义action。checkMsgAction(fromWho, msg)为抽象方法。所有继承TLBaseModule的用户模块所做的工作就是实现checkMsgAction(fromWho, msg)方法。格式如下;

@Override
protected TLMsg checkMsgAction(Object fromWho, TLMsg msg) {
    TLMsg returnMsg=null;
    switch (msg.getAction()) {
        case "startLog":
            returnMsg=startLog(fromWho,msg);
            break;
        case "transferLog":
            returnMsg=transferLog(fromWho,msg);
            break;
        case "startLogOnRun":
            returnMsg=startLogOnRun(fromWho,msg);
            break;
        case "addLogModule" :
            returnMsg=addLogModule(fromWho,msg);
            break;
        case "fromFactoryGetModule" :
            returnMsg= fromFactoryGetModule(fromWho,msg);
            break;
        default:
    }
    return returnMsg;
}

在checkMsgAction(Object fromWho, TLMsg msg)中,首先取出消息中的action,根据action的值运行对应的内部方法。action的值不是方法名,可以不与方法名一致。不同的action可以对应相同的方法。前面介绍过,每个action都有自己不同的前后期处理,方便编程的灵活性。例如同样是调用登录方法,对应游客发出的action,可以前期检测IP,而管理员发出的action,可不用检测,而这些改变不用修改原模块,在配置文件介绍中,我们可以看到可以灵活的设置前后期消息处理表。在我们后面介绍的数据库分表中,如果需要分表,则不用改变原模块代码,只需在配置文件加入一个前期消息,该消息启动分表模块,分析sql语句的分表字段来实现分表的处理,包括缓存也是这样处理的。下面来看数据库配置文件中一个表的配置

<tables>
        <table name="user"  dbtable="user" dbserver="dbserver1"
               readserver="dbserver2" beforeTrigger="userTableSplitTrigger"  />
        <table name="userm" dbtable="userm"  dbserver="dbserver1"  beforeTrigger="cachetrigger"
               afterTrigger="aftercachetrigger"/>
       <table name="userw" dbtable="userw"  dbserver="dbserver2" beforeTrigger="cachetrigger"
             afterTrigger="aftercachetrigger" />
</tables>

这个配置中  对于表user,有前触发器beforeTrigger="userTableSplitTrigger" 来分表,这个触发器的实现就是通过action的前期消息处理实现的。如果取消分表,则删除配置即可。user表是个虚表,分成了两个实表 userm和userw,分别位于不同的server上。对于这两个实表,配置了前后触发器cachetrigger、aftercachetrigger用于表的数据缓存。对于分表和缓存,都是通过前后期消息处理实现。对表user的SQL编程处理是透明的,没有更改原模块代码。这里我们没有像Spring那样,通过框架的功能强行改变模块的行为,完全是模块自身灵活的结果。

3、获取模块

   在我们的规范中,定义模块由统一创造,因此这里由模块工厂负责对象的实例化、初始化。每个模块需要其他模块的时候,由模块工厂中获取。相关的几个方法如下;

//获取单例模块。本地没有则从工厂中获取,模块名为名称
protected Object getModule(String moduleName)
//从工厂已经存在的模块中获取模块,不创建模块
protected Object getModuleInFactory(String moduleName)
//从工厂获取模块,创建模块
protected Object getModuleFromFactory(String moduleName)
//创建新模块,不工厂注册
protected Object getNewModule(String newModuleName,String moduleName)
//同一个类创建新模块。从本地获取模块,如果没有则从工厂中获取
protected Object getModule(String newModuleName,String moduleName) 

这些方法有细微的差别,有些模块是单例模式,有些模块要每次创建新的。默认情况模块是单例模式(配置中可设置模式,消息中也可指定模式),模块创建后存在工厂中,可被多人使用。

这些方法一般不用特意使用,在TLBaseModule中新增加了一个putMsg的多态方法。

protected TLMsg putMsg(String moduleName, TLMsg msg) {
    IObject module;
    if(msg.getParam("newModule")!=null && msg.getParam("newModule").equals("true"))
    {
        module= (IObject) getNewModule(moduleName,moduleName);
    }
    else
         module = (IObject) getModule(moduleName);
    if(module!=null)
       return putMsg(module, msg);
    else
        return null;
}

我们可以直接给一个模块名称发送消息,在方法内部自动获取模块实例。

4、其他

    (1) 继承类都要实现该模块的构造函数,构造函数用于工厂的创建用。如下:

public TLLog(){
    super();
}
public TLLog(String name ){
    super(name);
}
public TLLog(String name , TLObjectFactory modulefactory){
    super(name,modulefactory);
}

     (2)在系统消息处理中,有公共的方法,如果动态增加初始消息表、路由表等

    (3)模块中自带日志函数

protected void  putLog(String content ,LogLevel logLevel){
    putLog( content , logLevel, null);
}
protected void  putLog(String content ,LogLevel logLevel,String action){    
    putMsg("log", createMsg().setAction("setLog")
            .setParam("module",name)
            .setParam("logLevel",logLevel)
            .setParam("class",this.getClass())
            .setParam("action",action)
            .setParam("content",content)  );
}

putLog 给log模块发送消息,通用包下有log模块,也可以自定义log模块。包下的log模块是对log4j封装。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值