从零开始手写mmo游戏从框架到爆炸(六)— 消息处理工厂

news2024/11/18 1:25:16

        就好像门牌号一样,我们需要把消息路由到对应的楼栋和楼层,总不能像菜鸟一样让大家都来自己找数据吧。

        首先这里我们参考了rabbitmq中的topic与tag模型,topic对应类,tag对应方法。

新增一个模块,专门记录路由eternity-command

ServerTag.java

public interface ServerTag {

    /***
     * 打招呼
     */
    int TAG_HELLO_HI = 1;

}

ServerTopic.java

public interface ServerTopic {

    /***
     * 问候
     */
    int TOPIC_HELLO = 1;

}

然后再core中引入这个模块,同时增加反射依赖

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.reflections</groupId>
            <artifactId>reflections</artifactId>
            <version>0.9.10</version>
        </dependency>

        <dependency>
            <groupId>com.loveprogrammer</groupId>
            <artifactId>eternity-common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

        <dependency>
            <groupId>com.loveprogrammer</groupId>
            <artifactId>eternity-command</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

在core中增加一个文件夹

创建两个注解:

TagListener

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.METHOD;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface TagListener {

    /**
     * 订阅的tag
     */
    int tag() default 0;

    /**
     * 请求方消息类型
     */
    Class<?> messageClass() default Object.class;

}

TopicListener

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface TopicListener {

    /**
     * 订阅的主题
     */
    int topic() default 0;
}

接口IHandler

public interface IHandler {

}

抽象实现类BaseHandler

public abstract class BaseHandler implements IHandler{


}

hello实现类


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.command.server.ServerTag;
import com.loveprogrammer.command.server.ServerTopic;
import io.netty.channel.Channel;
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(Channel channel, String msg){
        log.info("say hi");
    }
}

创建监听器工厂 HandlerFactory


import com.loveprogrammer.base.network.command.anotation.TopicListener;
import org.reflections.Reflections;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

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

/**
 * @ClassName HandlerFactory
 * @Description 监听器工厂
 * @Author admin
 * @Date 2024/2/5 11:21
 * @Version 1.0
 */
@Component
public class HandlerFactory implements CommandLineRunner {

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

    public Map<Integer, Class> handlerMap = new HashMap<>();

    @Override
    public void run(String... args) throws Exception {
        // 找到所有实现类
        Reflections reflections = new Reflections("com.loveprogrammer.base.network.command.handler");
        // 获取在指定包扫描的目录所有的实现类
        Set<Class<? extends BaseHandler>> classes = reflections.getSubTypesOf(BaseHandler.class);
        for (Class<? extends IHandler > aClass : classes) {
            try {
                TopicListener listeners = aClass.getAnnotation(TopicListener.class);
                Integer topic = listeners.topic();
                handlerMap.put(topic, aClass);
                log.info("初始化消息监听器成功 {}",aClass.getName());
            } catch (Exception e) {
                log.error("初始化" + aClass.getName() + "消息监听器失败",e);
            }
        }
    }
}

启动server,查看监听器是否初始化成功。

2024-02-05 16:09:33.860  INFO 14144 --- [           main] c.l.base.network.command.HandlerFactory  : 初始化消息监听器成功 com.loveprogrammer.base.network.command.handler.HelloHandler
(♥◠‿◠)ノ゙  springboot启动成功   ლ(´ڡ`ლ)゙ 

上一篇:从零开始手写mmo游戏从框架到爆炸(五)— 集成springboot-CSDN博客

全部源码详见:

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

分支:step-06

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1438143.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

IS-IS P2P网路类型 地址不在同一子网建立邻居关系

拓扑图 由于IS-IS是直接运行在数据链路层上的协议&#xff0c;并且最早设计是给CLNP使用的&#xff0c;IS-IS邻居关系的形成与IP地址无关。但在实际的实现中&#xff0c;由于只在IP上运行IS-IS&#xff0c;所以是要检查对方的IP地址的。如果接口配置了从IP&#xff0c;那么只要…

使用navicat导出mysql离线数据后,再导入doris的方案

一、背景 doris本身是支持直接从mysql中同步数据的&#xff0c;但有时候&#xff0c;客户不允许我们使用doris直连mysql&#xff0c;此时就需要客户配合将mysql中的数据手工导出成离线文件&#xff0c;我们再导入到doris中 二、环境 doris 1.2 三、方案 doris支持多种导入…

万万没想到,又被问ThreadLocal了

我待ThreadLocal如初恋&#xff0c;ThreadLocal虐我千百遍。但这一次&#xff0c;要彻底搞懂ThreadLocal 回顾一下面试名场面&#xff1a; 面试官&#xff1a;Handler如何做到与线程绑定的&#xff1f; 我&#xff1a;每个Handler只有一个相关联的Looper&#xff0c;线程绑定…

【MySQL进阶之路】SpringBoot 底层如何去和 MySQL 交互了呢?

SpringBoot 底层如何去和 MySQL 交互了呢&#xff1f; 我们在写做 Java 项目时&#xff0c;一般都是引入 MyBatis 框架来和 MySQL 数据库交互&#xff0c;如果需要在 MySQL 上执行什么语句&#xff0c;只需要在 Mapper.xml 文件中定义对应的 SQL 语句即可 那么他底层到底是如…

学习Android的第六天

目录 Android TextView 文本框 TextView 基础属性 范例 带阴影的TextView 范例 带边框的TextView 范例 带图片(drawableXxx)的TextView 范例1 范例2 使用autoLink属性识别链接类型 范例 TextView 显示简单的 HTML 范例1 范例2 SpannableString & Spannable…

Git合并多个commit

git rebase -i commitId 假设想要合并最后3个commit&#xff0c; git log显示 commit id 1 commit id 2 commit id 3 commit id 4 则执行git rebase -i commitId4. 注意是4&#xff0c;不是3. 然后&#xff0c;pick最老的commit (commit id 3). https://blog.csdn.net/qiao…

盲盒APP软件开发:开启全新购物体验

随着科技的飞速发展&#xff0c;盲盒APP软件成为了市场的新宠。盲盒APP软件开发不仅为消费者提供了全新的购物体验&#xff0c;同时也为商家带来了无限的商业机会。本文将深入探讨盲盒APP软件开发的各个方面&#xff0c;包括其概念、优势、开发流程以及未来发展趋势。 一、盲盒…

java Servlet 云平台教学系统myeclipse定制开发SQLServer数据库网页模式java编程jdbc

一、源码特点 JSP 云平台教学系统是一套完善的web设计系统&#xff0c;对理解JSP java编程开发语言有帮助 系统采用serlvet dao bean&#xff0c;系统具有完整的源代码和数据库 &#xff0c;系统主要采用B/S模式开发。开发 环境为TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据…

ref用法

目录 React中提供两种方法创建ref对象&#xff1a; 类组件获取 Ref 三种方式 ① Ref属性是一个字符串。 ② Ref 属性是一个函数。 ③ Ref属性是一个ref对象。 高级用法1&#xff1a;forwardRef 转发 Ref 高级用法2&#xff1a;ref实现组件通信 【ref作用】&#xff1a;最…

Vue3.4+element-plus2.5 + Vite 搭建教程整理

一、 Vue3Vite 项目搭建 说明&#xff1a; Vue3 最新版本已经基于Vite构建&#xff0c;关于Vite简介&#xff1a;Vite 下一代的前端工具链&#xff0c;前端开发与构建工具-CSDN博客 1.安装 并 创建Vue3 应用 npm create vuelatest 创建过程可以一路 NO 目前推荐使用 Vue R…

20240203在WIN10下使用GTX1080配置stable-diffusion-webui.git不支持float16精度出错的处理

20240203在WIN10下使用GTX1080配置stable-diffusion-webui.git不支持float16精度出错的处理 2024/2/3 21:23 缘起&#xff1a;最近学习stable-diffusion-webui.git&#xff0c;在Ubuntu20.04.6下配置SD成功。 不搞精简版本&#xff1a;Miniconda了。直接上Anacoda&#xff01; …

如何在 emacs 上开始使用 Tree-Sitter(windows)

文章目录 如何在emacs上开始使用Tree-Sitter&#xff08;windows&#xff09; 如何在emacs上开始使用Tree-Sitter&#xff08;windows&#xff09; 参考&#xff1a;“How to Get Started with Tree-Sitter”。 首先要有一个可运行的emacs&#xff0c;并且它支持Tree-Sitter&…

最新AI系统ChatGPT网站H5系统源码,支持Midjourney绘画局部编辑重绘,GPT语音对话+ChatFile文档对话总结+DALL-E3文生图

一、前言 SparkAi创作系统是基于ChatGPT进行开发的Ai智能问答系统和Midjourney绘画系统&#xff0c;支持OpenAI-GPT全模型国内AI全模型。本期针对源码系统整体测试下来非常完美&#xff0c;那么如何搭建部署AI创作ChatGPT&#xff1f;小编这里写一个详细图文教程吧。已支持GPT…

第3节、电机定速转动【51单片机+L298N步进电机系列教程】

↑↑↑点击上方【目录】&#xff0c;查看本系列全部文章 摘要&#xff1a;本节介绍用定时器定时的方式&#xff0c;精准控制脉冲时间&#xff0c;从而控制步进电机速度。 一、计算过程 电机每一步的角速度等于走这一步所花费的时间&#xff0c;走一步角度等于步距角&#xff…

获取旁站 / C 段:第三方网站(附链接)

一、介绍 1.1 旁段 在网络安全的上下文中&#xff0c;"旁段"&#xff08;Pivot&#xff09;是指攻击者通过入侵一个网络中的一台计算机&#xff0c;然后利用该计算机作为跳板&#xff08;或者称之为“旁道”&#xff09;来访问其他计算机或网络资源的行为。 攻击者…

二进制安全虚拟机Protostar靶场(8)heap3 Fastbins unlink exploit

前言 这是一个系列文章&#xff0c;之前已经介绍过一些二进制安全的基础知识&#xff0c;这里就不过多重复提及&#xff0c;不熟悉的同学可以去看看我之前写的文章 heap3 程序静态分析 https://exploit.education/protostar/heap-three/#include <stdlib.h> #include …

二进制安全虚拟机Protostar靶场(7)heap2 UAF(use-after-free)漏洞

前言 这是一个系列文章&#xff0c;之前已经介绍过一些二进制安全的基础知识&#xff0c;这里就不过多重复提及&#xff0c;不熟悉的同学可以去看看我之前写的文章 heap2 程序静态分析 https://exploit.education/protostar/heap-two/#include <stdlib.h> #include &…

亚信安慧AntDB领航分布式数据库的突破之路

随着互联网技术的迅猛发展&#xff0c;大数据时代的到来&#xff0c;数据库的需求不断增长。在这样的背景下&#xff0c;国产分布式数据库正逐渐崭露头角&#xff0c;AntDB作为其中的重要代表&#xff0c;也积极参与到了这场竞争中。作为国内的技术创新者&#xff0c;AntDB不仅…

UE4 C++ 动态加载类和资源

动态加载类和资源&#xff1a;指在运行时加载 .cpp void AMyActor::BeginPlay() {Super::BeginPlay();//动态加载资源UStaticMesh* MyTempStaticMesh LoadObject<UStaticMesh>(nullptr,TEXT("/Script/Engine.StaticMesh/Game/StarterContent/Shapes/Shape_NarrowC…

2024过年期间可以开通股票账户吗?找哪家证券公司开户佣金手续费最低?

炒股前的准备工作包括以下几个方面&#xff1a; 学习基础知识&#xff1a;了解股市的基本知识&#xff0c;包括股票的基本概念、交易方式、股市规则等&#xff0c;可以通过阅读相关书籍、参加培训班或利用在线教育资源进行学习。 制定投资策略&#xff1a;根据个人的风险承受能…