# 阻断机制 阻断机制是核心框架提供的一种可以使得将监听函数进行分组管理的机制,通过此机制你可以做到例如:机器人开关指令、群内游戏状态变化等等。 > 阻断机制某种意义上来讲可以说是对监听函数的分组,此机制可能存在些许BUG。 ## 注解 * ### @Block > 阻断注解,用于定义一个监听函数的阻断名称 > 此注解并不是必须的,但是如果你需要使用阻断机制,我建议你加上。毕竟阻断机制阻断一个函数集是依据阻断名称来分类的。 > 参数: | 参数 | 类型 | 默认值 | 含义 | | --- | --- | --- | --- | | `value` | `String[]` | `{}` | 被标注的函数的阻断名。阻断名可以有多个。 | <br> * ### @BlockFilter > 此注解的参数、含义与`@Filter`完全相同,唯一一点不同的就是此注解是当标注的函数进入了阻断状态的时候才生效。 > 当消息接收,且函数为阻断状态,那么事件过滤器会优先用时`@BlockFilter`来过滤消息,假如没有则会尝试使用`@Filter`的过滤机制来过滤。 使用以上注解来对一个监听函数定义他的阻断名,然后通过在函数中使用送信器`MsgSender`来使函数进入或结束阻断状态。 `MsgSender`中与阻断相关的方法: ```java //**************** 普通阻塞 ****************// /** * 开启阻塞-普通阻塞 * 仅仅添加当前这一个监听函数,不根据名称关联其他 函数 */ public void onBlockOnlyThis(boolean append); /** * 开启阻塞-普通阻塞 * 仅仅添加当前这一个监听函数,不根据名称关联其他 * 如果存在其他阻塞函数,替换他们 为当前加入的函数 */ public void onBlockOnlyThis(); /** * 开启阻塞-普通阻塞 * 根据当前函数的阻塞名称添加全部同名函数 */ public void onBlockByThisName(boolean append); /** * 开启阻塞-普通阻塞 * 根据当前函数的阻塞名称添加全部同名函数 * 如果存在其他阻塞函数,替换他们 为当前加入的函数 */ public void onBlockByThisName(); /** * 根据组名来使某个分组进入阻断状态 * 此方法当前执行的监听函数没有关联 */ public void onBlockByName(String name, boolean append); /** * 根据组名来使某个分组进入阻断状态 * 如果存在其他阻塞函数,替换他们 为当前加入的函数 */ public void onBlockByName(String name) //**************** 全局阻塞 ****************// /** * 根据一个名称更新全局阻塞 */ public void onGlobalBlockByName(String name); /** * 根据阻断名称的索引来更新全局阻塞 * 毕竟阻断注解中可以有多个名称 */ public void onGlobalBlockByNameIndex(int index) throws NoSuchBlockNameException; /** * 根据第一个阻断名称来更新全剧阻塞 */ public void onGlobalBlockByFirstName(); //**************** 获取阻断器部分信息 ****************// /** * 根据组名判断自己所在的组是否全部在阻断状态中 */ public boolean isAllOnBlockByName(); /** * 根据组名判断自己所在的组是否有任意在阻断状态中 */ public boolean isAnyOnBlockByName(); /** * 根据组名判断自己所在的组是否全部没有在阻断状态中 */ public boolean isNoneOnBlockByName(); /** * 判断自己是否存在于阻断队列 */ public boolean isOnBlock(); /** * 判断自己是否作为单独的阻断被阻断了 */ public boolean isOnlyThisOnBlock(); //**************** 获取阻断状态的两个方法使用真实阻断器 ****************// /** * 获取当前处于全局阻断状态下的阻断组名 * * @return 阻断组名 */ public String getOnGlobalBlockName(); /** * 获取当前处于普通阻断状态下的阻断组名列表 * @return 处于普通阻断状态下的阻断组名列表 */ public String[] getOnNormalBlockNameArray(); //**************** 取消阻断相关 ****************// /** * 取消普通阻塞-即清空阻塞中的普通阻塞函数容器 * 使用真实阻断器,即此方法不论当前送信器中是否存在监听函数,都会生效。下面两个取消阻塞的方法同理 */ public void unBlock(); /** * 移除全局阻塞 -即清空阻塞中的全局阻塞函数 容器 */ public void unGlobalBlock(); /** * 取消全部阻塞 */ public void unAllBlock(); ``` ### 解释 * ##### 送信器与真实阻断器 上面的方法中,有一些东西我认为我需要解释一下。 首先,在送信器中,每一个监听函数都会记录当前获取了送信器的监听函数。这也就是为什么上面的方法中很多方法是直接获取"当前执行的监听函数"以进入阻断状态的了。 但是,有些时候的送信器中是不存在监听函数的,例如启动器启动成功的回调函数所提供的送信器中就不存在什么监听函数,那么这该怎么办? 上面的方法中,有时候会看到"使用真实阻断器"这种说法。所谓的真实阻断器就是真正在使用的阻断器,而当送信器中不存在监听函数的时候,大部分方法使用的是"空阻断器",也就是说,当不存在监听函数的送信器如果执行了阻断相关的方法,如果没有提到使用的是否为"真实阻断器"的话,那么执行的阻断方法将会没有任何效果。 > 这是肯定的啦 * ##### 普通阻塞与全局阻塞 阻塞的方式有两种:普通阻塞和全局阻塞 > 当普通阻塞与全局阻塞同时存在的时候,仅全局阻塞生效。 **`普通阻塞**` 普通阻塞相对于全局阻塞来讲,优先级低,灵活性高。普通阻塞可以通过多种方式将监听函数添加进入阻塞状态:按照名称、按照自己、是否关联同名阻塞函数、是追加还是替换等等。 **`全局阻塞**` 全局阻塞的优先级比较高,但是没有那么高的灵活性。全局阻塞只能通过单个函数或阻塞函数的组名来进入阻塞状态,且无法追加。当你要将另外一组函数加入全局阻塞状态的时候,就会顶替掉当前的全局阻塞函数。 ### 举个栗子 ```java /** * 阻塞demo **/ @Beans @Listen(MsgGetTypes.privateMsg) public class BlockTest { /** * 收到 hello的私聊消息的时候,会在控制台打印“hello” */ @Filter("hello") public void hello(MsgSender msgSender){ System.out.println("hello"); } /** * name1组进入阻塞状态 */ @Filter("onBlock") @Block("name1") public void in(MsgSender msgSender){ msgSender.onBlockByThisName(); } /** * 清空阻断状态 */ @Filter("off") @Block("name1") public void off(MsgSender msgSender){ msgSender.unBlock(); } } ``` > 上面的demo中,当私信一句"hello"的时候,控制台会打印一句"hello"(hello方法实现) > 当私信收到一句"onBlock"的时候,阻塞组名为"name1"的函数进入阻塞状态,此时其他函数将会失效。再私信一句"hello"的时候将没有任何反应。\`\` > 当私信一句"off"的时候,由于off方法阻塞组名为name1,此时会清空阻塞函数,此后再私信一句"hello"的时候,控制台又会打印hello了