从零开始手写mmo游戏从框架到爆炸(九)— 消息路由最终实现

导航:从零开始手写mmo游戏从框架到爆炸(零)—— 导航-CSDN博客

        从第六章到第八章,都是在为消息路由准备,现在我们已经距离目标不远了。我们已经在HandlerFactory中注册了所有的handler,此时只需要把投递过来的消息根据topic和tag找到对应的handler去执行就可以了,但是这里还有一个新的问题,就是投递过来的消息body都是string,但是我们很多时候传递过来的应该是对象的json字符串,所以我们要考虑反序列化的问题。同时为了尽可能的使用服务器的资源,处理的时候应该放到线程池中去处理,所以还需要增加一个线程池。

改造NetworkListener

package com.loveprogrammer.base.network.support;

import com.alibaba.fastjson2.JSON;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.loveprogrammer.base.bean.session.Session;
import com.loveprogrammer.base.factory.SpringContextHelper;
import com.loveprogrammer.base.network.command.HandlerFactory;
import com.loveprogrammer.base.network.command.anotation.TagListener;
import com.loveprogrammer.base.network.listener.INetworkEventListener;
import com.loveprogrammer.constants.CommonValue;
import com.loveprogrammer.pojo.StringMessage;
import io.netty.channel.ChannelHandlerContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@Component
public class NetworkListener implements INetworkEventListener {

    protected static final Logger logger = LoggerFactory.getLogger(NetworkListener.class);

    private final ThreadPoolExecutor executor = new ThreadPoolExecutor(
            1,
            10,
            0L,
            TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(20480),
            new ThreadFactoryBuilder()
                    .setNameFormat("worker-pool-%d").build(),
            new ThreadPoolExecutor.CallerRunsPolicy()
    );

    @Autowired
    private HandlerFactory handlerFactory;


    @Override
    public void onConnected(ChannelHandlerContext ctx) {
        logger.info("建立连接");
        SessionManager.getInstance().create(ctx.channel());
    }

    @Override
    public void onDisconnected(ChannelHandlerContext ctx) {
        logger.info("建立断开");
        SessionManager.getInstance().close(ctx.channel());
    }

    @Override
    public void onExceptionCaught(ChannelHandlerContext ctx, Throwable throwable) {
        logger.warn("异常发生", throwable);
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, StringMessage msg) {
//        logger.info("数据内容:data=" + msg.getBody());
//        String result = "我是服务器,我收到了你的信息:" + msg.getBody();
//
//        Session session = SessionManager.getInstance().getSessionByChannel(ctx.channel());
//        result += ",sessionId = " + session.getId();
//
//        StringMessage message = StringMessage.create(1,1);
//        message.setStatusCode(CommonValue.MSG_STATUS_CODE_SUCCESS);
//        message.setBody(result);
//
//        SessionManager.getInstance().sendMessage(ctx.channel(),message);

        // 消息分发 对于消息的处理要增加多线程
        int topicId = msg.getTopicId();
        int tagId = msg.getTagId();

        Class handler = handlerFactory.handlerMap.get(topicId);
        if (handler == null) {
            logger.warn("未获取到指定的消息监听对象,topicId {}", topicId);
            return;
        }
        String bodyValue = msg.getBody();
        executor.execute(() -> {
            try {
                Object bean = SpringContextHelper.getBean(handler);
                // 找到tag 遍历methods
                Method[] methods = handler.getMethods();
                for (Method method : methods) {
                    TagListener mqListener = method.getAnnotation(TagListener.class);
                    if (tagId == mqListener.tag()) {
                        Class aClass = mqListener.messageClass();
                        String name = aClass.getName();
                        // 先处理基本类型
                        if ("java.lang.String".equals(name)) {
                            method.invoke(bean, ctx, bodyValue);
                        } else if ("java.lang.Long".equals(name)) {
                            Long object = Long.parseLong(bodyValue);
                            method.invoke(bean, ctx, object);
                        } else if ("java.lang.Integer".equals(name)) {
                            Integer object = Integer.parseInt(bodyValue);
                            method.invoke(bean, ctx, object);
                        } else if ("java.lang.Short".equals(name)) {
                            Short object = Short.parseShort(bodyValue);
                            method.invoke(bean, ctx, object);
                        } else if ("java.lang.Byte".equals(name)) {
                            Byte object = Byte.parseByte(bodyValue);
                            method.invoke(bean, ctx, object);
                        } else if ("java.lang.Double".equals(name)) {
                            Double object = Double.parseDouble(bodyValue);
                            method.invoke(bean, ctx, object);
                        } else if ("java.lang.Float".equals(name)) {
                            Float object = Float.parseFloat(bodyValue);
                            method.invoke(bean, ctx, object);
                        }
                        // 转对象类型
                        else {
                            Object object = JSON.parseObject(bodyValue, aClass);
                            method.invoke(bean, ctx, object);
                        }
                        break;
                    }
                }
            } catch (Exception e) {
                logger.error("发生异常", e);
                String result = "我是服务器,我收到了你的信息:" + msg.getBody();
                result += ",发生异常 = " + e.getMessage();
                StringMessage message = StringMessage.create(0, 0);
                message.setStatusCode(CommonValue.MSG_STATUS_CODE_SUCCESS);
                message.setBody(result);
                SessionManager.getInstance().sendMessage(ctx.channel(), message);
            }
        });

    }
}

改造HelloHandler

package com.loveprogrammer.base.network.command.handler;

import com.loveprogrammer.base.bean.session.Session;
import com.loveprogrammer.base.network.command.BaseHandler;
import com.loveprogrammer.base.network.command.HandlerFactory;
import com.loveprogrammer.base.network.command.anotation.TagListener;
import com.loveprogrammer.base.network.command.anotation.TopicListener;
import com.loveprogrammer.base.network.support.SessionManager;
import com.loveprogrammer.command.server.ServerTag;
import com.loveprogrammer.command.server.ServerTopic;
import com.loveprogrammer.constants.CommonValue;
import com.loveprogrammer.pojo.StringMessage;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

/**
 * @ClassName HelloHandler
 * @Description 测试handler
 * @Author admin
 * @Date 2024/2/5 15:49
 * @Version 1.0
 */
@Component
@TopicListener(topic = ServerTopic.TOPIC_HELLO)
public class HelloHandler extends BaseHandler {

    public static final Logger log = LoggerFactory.getLogger(HelloHandler.class);

    @TagListener(tag = ServerTag.TAG_HELLO_HI,messageClass = String.class)
    public void sayHi(ChannelHandlerContext ctx, String msg){
        log.info("数据内容:data=" + msg);
        String result = "我是服务器,我收到了你的信息:" + msg;
        Session session = SessionManager.getInstance().getSessionByChannel(ctx.channel());
        result += ",sessionId = " + session.getId();
        StringMessage message = StringMessage.create(0,0);
        message.setStatusCode(CommonValue.MSG_STATUS_CODE_SUCCESS);
        message.setBody(result);
        SessionManager.getInstance().sendMessage(ctx.channel(),message);
    }
}

全部源码详见:

gitee : eternity-online: 多人在线mmo游戏 - Gitee.com

分支:step-06

你可能感兴趣的:(从零开始MMO游戏,游戏,java,mmo,spring,boot,后端)