Java游戏服务器开发之十一-- 将消息分发给线程队列执行及路由功能

添加的类有:
com.lizhaoblog.base.concurrent.commond.ICommand
com.lizhaoblog.base.concurrent.commond.IHandler
com.lizhaoblog.base.concurrent.dictionary.IMessageDictionary
com.lizhaoblog.base.concurrent.handler.AbstractHandler
com.lizhaoblog.base.network.processor.IProcessor
com.lizhaoblog.server.biz.constant.CommonValue
com.lizhaoblog.server.biz.dictionary.MessageHandlerDictionary
com.lizhaoblog.server.biz.handler.TestFirstHandler
com.lizhaoblog.server.core.processor.LogicProcessor;
  修改的类有
NetworkConsumer



  这次改的东西比较多了。
我们一个个来看,我们的主线目标,将消息通过不同的id来找到对应的执行类(handler/control),然后扔到线程池中执行。
这样我们写的话就是2个, 一个将消息放到线程池中执行,一个是消息通过不同的id来找到对应的执行类(handler/control)

所以我们先有一个线程池队列,使用IProcessor,里面只有一个方法process,然后看到实现类LogicProcessor,先是声明了一个具体的线程池变量(ThreadPoolExecutor),里面的方法就是执行线程具体线程(executor.execute(handler);)
线程池要执行的需要是一个线程,这个线程需要我们自己实现,所以我们写一个接口ICommand继承Runnable,然后后面的子类继承于ICommand。
在ICommand中就2个方法,一个是执行操作doAction,一个是runable的run方法。这2个都写着,让子类实现就好。
再看下IHandler,IHandler是ICommand的子类,是我们现在所有handler的接口,因为我们是消息传输,肯定会有message和session,所以就在里面写了get/set方法。
但我们写上多个handler后,其实会发现里面的执行逻辑都是一样的,就是在run里面调用doAction方法。就写了一个AbstractHandler,声明
protected T message; protected V param;,然后再run方法里面调用doAction
后面我们要写handler的话(TestFirstHandler),只要继承AbstractHandler然后实现里面的doAction方法
  
但我们的消息传输上来,我们不确定要通过哪个handler来执行,这时候就需要一个消息字典来进行区分IMessageDictionary(就像web中使用网址区分url一样),具体实现MessageHandlerDictionary就是管理一个map,然后根据键来获取handler。

  可以看下具体代码的实现了

com.lizhaoblog.base.concurrent.commond.ICommand

/*
 * Copyright (C), 2015-2018
 * FileName: ICommand
 * Author:   zhao
 * Date:     2018/6/25 15:37
 * Description: 继承runable接口,可以放在线程池中执行
 * History:
 * <author>          <time>          <version>          <desc>
 * 作者姓名           修改时间           版本号              描述
 */
package com.lizhaoblog.base.concurrent.commond;

/**
 * 〈一句话功能简述〉<br>
 * 〈继承Runnable接口,可以放在线程池中执行〉
 *
 * @author zhao
 * @date 2018/6/25 15:37
 * @since 1.0.0
 */
public interface ICommand extends Runnable {
  /**
   * 执行具体的方法
   */
  void doAction();

  /**
   * 运行
   */
  @Override
  default void run() {
    doAction();
  }
}

com.lizhaoblog.base.concurrent.commond.IHandler

/*
 * Copyright (C), 2015-2018
 * FileName: IHandler
 * Author:   zhao
 * Date:     2018/6/25 15:35
 * Description: 队列执行器
 * History:
 * <author>          <time>          <version>          <desc>
 * 作者姓名           修改时间           版本号              描述
 */
package com.lizhaoblog.base.concurrent.commond;

/**
 * 〈一句话功能简述〉<br>
 * 〈队列执行器〉
 *
 * @author zhao
 * @date 2018/6/25 15:35
 * @since 1.0.0
 */
public interface IHandler<T,V> extends ICommand {

  /**
   * 消息
   * @return 消息request
   */
  T getMessage();

  /**
   * 设置消息request
   * @param message request
   */
  void setMessage(T message);

  /**
   * 参数
   * @return 参数
   */
  V getParam();

  /**
   *  设置参数
   * @param parm 参数
   */
  void setParam(V parm);

}

com.lizhaoblog.base.concurrent.dictionary.IMessageDictionary

/*
 * Copyright (C), 2015-2018
 * FileName: IMessageDictionary
 * Author:   zhao
 * Date:     2018/6/25 14:51
 * Description: 消息字典接口
 * History:
 * <author>          <time>          <version>          <desc>
 * 作者姓名           修改时间           版本号              描述
 */
package com.lizhaoblog.base.concurrent.dictionary;

import com.lizhaoblog.base.concurrent.commond.IHandler;

/**
 * 〈一句话功能简述〉<br>
 * 〈消息字典接口〉
 *
 * @author zhao
 * @date 2018/6/25 14:51
 * @since 1.0.0
 */
public interface IMessageDictionary {

  /**
   * 注册 id--handle
   * @param messageId
   * @param handler
   */
  void register(int messageId,  Class<? extends IHandler> handler);
  /**
   * 根据messageId获取handler
   * @param messageId
   * @return
   */
  IHandler getHandlerFromMessageId(Integer messageId);
}

com.lizhaoblog.base.concurrent.handler.AbstractHandler

/*
 * Copyright (C), 2015-2018
 * FileName: AbstractHandler
 * Author:   zhao
 * Date:     2018/6/25 15:54
 * Description: 继承ICommand,将一些通用的处理过程写在里面
 * History:
 * <author>          <time>          <version>          <desc>
 * 作者姓名           修改时间           版本号              描述
 */
package com.lizhaoblog.base.concurrent.handler;

import com.lizhaoblog.base.concurrent.commond.IHandler;

/**
 * 〈一句话功能简述〉<br>
 * 〈继承ICommand,将一些通用的处理过程写在里面〉
 *
 * @author zhao
 * @date 2018/6/25 15:54
 * @since 1.0.0
 */
public abstract class AbstractHandler<T, V> implements IHandler<T, V> {
  protected T message;

  protected V param;

  /**
   * 执行具体的操作,交由子类实现
   */
  @Override
  public abstract void doAction();

  @Override
  public void run() {
    doAction();
  }

  @Override
  public T getMessage() {
    return message;
  }

  @Override
  public void setMessage(T message) {
    this.message = message;
  }

  @Override
  public V getParam() {
    return param;
  }

  @Override
  public void setParam(V param) {
    this.param = param;
  }

}

com.lizhaoblog.base.network.processor.IProcessor

/*
 * Copyright (C), 2015-2018
 * FileName: IProcessor
 * Author:   zhao
 * Date:     2018/6/25 15:34
 * Description: 进程接口
 * History:
 * <author>          <time>          <version>          <desc>
 * 作者姓名           修改时间           版本号              描述
 */
package com.lizhaoblog.base.network.processor;

import com.lizhaoblog.base.concurrent.commond.IHandler;

/**
 * 〈一句话功能简述〉<br>
 * 〈进程接口〉
 *
 * @author zhao
 * @date 2018/6/25 15:34
 * @since 1.0.0
 */
public interface IProcessor {
  /**
   * 执行具体的指令
   * @param handler 具体的执行
   */
  void process(IHandler handler);

}

com.lizhaoblog.server.biz.constant.CommonValue

/*
 * Copyright (C), 2015-2018
 * FileName: CommonValue
 * Author:   zhao
 * Date:     2018/6/25 16:45
 * Description: 放置常量
 * History:
 * <author>          <time>          <version>          <desc>
 * 作者姓名           修改时间           版本号              描述
 */
package com.lizhaoblog.server.biz.constant;

/**
 * 〈一句话功能简述〉<br>
 * 〈放置常量〉
 *
 * @author zhao
 * @date 2018/6/25 16:45
 * @since 1.0.0
 */
public class CommonValue {

  public static final int CM_MSG_TEST = 10001;

  private CommonValue() {
  }
}

com.lizhaoblog.server.biz.dictionary.MessageHandlerDictionary

/*
 * Copyright (C), 2015-2018
 * FileName: MessageHandlerDictionary
 * Author:   zhao
 * Date:     2018/6/25 16:39
 * Description: 消息字典绑定
 * History:
 * <author>          <time>          <version>          <desc>
 * 作者姓名           修改时间           版本号              描述
 */
package com.lizhaoblog.server.biz.dictionary;

import com.lizhaoblog.base.concurrent.commond.IHandler;
import com.lizhaoblog.base.concurrent.dictionary.IMessageDictionary;
import com.lizhaoblog.server.biz.constant.CommonValue;
import com.lizhaoblog.server.biz.handler.TestFirstHandler;
import com.lizhaoblog.server.pojo.ServerConfig;

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

import javax.annotation.PostConstruct;

/**
 * 〈一句话功能简述〉<br>
 * 〈消息字典绑定〉
 *
 * @author zhao
 * @date 2018/6/25 16:39
 * @since 1.0.0
 */
@Component
@Scope("singleton")
public class MessageHandlerDictionary implements IMessageDictionary {
  private final Map<Integer, Class<? extends IHandler>> idHandleMap = new HashMap<>(10);

  @PostConstruct
  public void init() {
    register(CommonValue.CM_MSG_TEST, TestFirstHandler.class);
  }

  @Override
  public void register(int messageId, Class<? extends IHandler> handler) {
    idHandleMap.put(messageId, handler);
  }

  @Override
  public IHandler getHandlerFromMessageId(Integer messageId) {
    Class<? extends IHandler> clazz = idHandleMap.get(messageId);
    if (clazz != null) {
      try {
        return (IHandler) ServerConfig.getInstance().getApplicationContext().getBean(clazz.getSimpleName());
      } catch (Exception e) {
        return null;
      }
    }
    return null;
  }
}

com.lizhaoblog.server.biz.handler.TestFirstHandler

/*
 * Copyright (C), 2015-2018
 * FileName: TestFirstHandler
 * Author:   zhao
 * Date:     2018/6/25 16:24
 * Description: 用于测试的第一个handler
 * History:
 * <author>          <time>          <version>          <desc>
 * 作者姓名           修改时间           版本号              描述
 */
package com.lizhaoblog.server.biz.handler;

import com.lizhaoblog.base.concurrent.handler.AbstractHandler;
import com.lizhaoblog.base.session.Session;
import com.lizhaoblog.base.session.SessionManager;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

/**
 * 〈一句话功能简述〉<br>
 * 〈用于测试的第一个handler〉
 *
 * @author zhao
 * @date 2018/6/25 16:24
 * @since 1.0.0
 */
@Component("TestFirstHandler")
public class TestFirstHandler extends AbstractHandler<String, Session> {

  private static final Logger logger = LoggerFactory.getLogger(TestFirstHandler.class);

  @Override
  public void doAction() {
    //    logger.info("TestFirstHandler doAction " + this);
    logger.info("服务器收到的数据内容:data=" + message);
    String result = "小李,我是服务器,我收到你的信息了。";
    SessionManager.getInstance().sendMessage(param, result);
  }
}

com.lizhaoblog.server.core.processor.LogicProcessor;
/*
 * Copyright (C), 2015-2018
 * FileName: LogicProcessor
 * Author:   zhao
 * Date:     2018/6/25 16:57
 * Description: 具体的消息处理器,进程
 * History:
 * <author>          <time>          <version>          <desc>
 * 作者姓名           修改时间           版本号              描述
 */
package com.lizhaoblog.server.core.processor;

import com.lizhaoblog.base.concurrent.commond.IHandler;
import com.lizhaoblog.base.network.processor.IProcessor;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 〈一句话功能简述〉<br>
 * 〈具体的消息处理器,进程〉
 *
 * @author zhao
 * @date 2018/6/25 16:57
 * @since 1.0.0
 */
public class LogicProcessor implements IProcessor {

  private ExecutorService executor = new ThreadPoolExecutor(8, 8, 0L, TimeUnit.MILLISECONDS,
          new LinkedBlockingQueue<>(100000), new ThreadPoolExecutor.CallerRunsPolicy());

  @Override
  public void process(IHandler handler) {
    this.executor.execute(handler);
  }

}
NetworkConsumer

/*
 * Copyright (C), 2015-2018
 * FileName: INetworkConsumer
 * Author:   zhao
 * Date:     2018/6/23 21:06
 * Description: 网络消息处理器
 * History:
 * <author>          <time>          <version>          <desc>
 * 作者姓名           修改时间           版本号              描述
 */
package com.lizhaoblog.server.core.customer;

import com.lizhaoblog.base.concurrent.commond.IHandler;
import com.lizhaoblog.base.network.processor.IProcessor;
import com.lizhaoblog.base.concurrent.dictionary.IMessageDictionary;
import com.lizhaoblog.base.constant.ConstantValue;
import com.lizhaoblog.base.network.customer.INetworkConsumer;
import com.lizhaoblog.base.session.Session;
import com.lizhaoblog.base.session.SessionManager;
import com.lizhaoblog.server.biz.constant.CommonValue;
import com.lizhaoblog.server.core.processor.LogicProcessor;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

import javax.annotation.PostConstruct;

import io.netty.channel.Channel;

/**
 * 〈一句话功能简述〉<br>
 * 〈网络消息处理器,实现类〉
 *
 * @author zhao
 * @date 2018/6/23 21:09
 * @since 1.0.0
 */
@Component
@Scope("singleton")
public class NetworkConsumer implements INetworkConsumer {
  private static final Logger logger = LoggerFactory.getLogger(NetworkConsumer.class);

  private Map<Integer, IProcessor> processors = new HashMap<>(10);

  @Autowired
  private IMessageDictionary messageDictionary;

  public void registerProcessor(int queueId, IProcessor processor) {
    processors.put(queueId, processor);
  }

  @PostConstruct
  public void init() {
    registerProcessor(ConstantValue.QUEUE_LOGIC, new LogicProcessor());
  }

  @Override
  public void consume(String message, Channel channel) {
    //获取session,后面需要根据session中的channel进行消息发送
    Session session = SessionManager.getInstance().getSessionByChannel(channel);
    if (session == null) {
      logger.debug("consume session is not found");
      return;
    }
    IHandler handler = messageDictionary.getHandlerFromMessageId(CommonValue.CM_MSG_TEST);
    handler.setMessage(message);
    handler.setParam(session);
    IProcessor processor = processors.get(ConstantValue.QUEUE_LOGIC);
    processor.process(handler);
  }
}


    上面的代码在码云上 https://gitee.com/lizhaoandroid/JgServer
可以加qq群一起探讨Java游戏服务器开发的相关知识 676231524

猜你喜欢

转载自blog.csdn.net/cmqwan/article/details/80808732