DOIFOR技术IDEA插件开发中的消息传递
DOIFOR技术IDEA插件开发中的消息传递
IDEA

IDEA插件开发中的消息传递

技术

IDEA插件开发界面使用了Java的Swing,Swing是一种事件驱动的UI框架。在IDEA插件开发中事件通知有两种模式:

  • 回调函数
  • 消息队列

由于回调函数的写法会导致代码耦合度变高,不利于后期维护。少量事件或者界面较为间的时候使用回调函数可以简单快速的实现功能,也会让代码可读性变高。但是事件较多的时候,回调函数就不适用了,这个时候消息队列就能起到很好的解耦作用。下面将展示IDEA平台中消息组件的使用。

消息队列中有三个要素:主题、发布者、消费者。

主题(Topic)

消息包含三个主要属性:

  • 显示名称(DisplayName):用于日志记录/监视目的的人类可读名称。
  • 传播方向(BroadcastDirection):有四个可用选项:TO_CHILDREN、TO_DIRECT_CHILDREN、NONE、TO_PARENT,默认值为:TO_CHILDREN
  • 监听类(Handler):用于描述某个主题的具体业务。

如何创建一个主题呢?首先,咱们需要定义一个监听类接口:

public interface MessageHandler {
    void handle(String message);
}

handle()方法的参数可以任意定义,后续消息组件调用时就是寻找有相同参数的实现来完成对应业务逻辑。

接下来咱们需要定义一个Topc了,这个可以定义在任意位置,一般情况下推荐与生产者定义在一起:

public class MessageProducer {
    // @Topic.AppLevel
    Topic messageTopic = new Topic<>("message", MessageHandler.class, Topic.BroadcastDirection.TO_CHILDREN);
}

定义Topic时传播方向一般默认就行,只有监听类是必填的。Topic可以用@Topic.AppLevel@Topic.ProjectLevel来标记主题适用范围,不过这个注解是SOURCE级别的,也就是说编译后就没有,不会对业务造成什么影响,相当于注释。

发布者

消息发布流程

消息总线分三种类型:Application、Project、Module。现在Module的消息总线基本上不推荐使用了,官方已经将Module.getMessageBus标记为废弃方法了。

代码如下:

public void sendMessage() {
    // 应用级
    ApplicationManager.getApplication().getMessageBus().syncPublisher(messageTopic).handle("hello world");

    // 项目级
    Project project = null;
    project.getMessageBus().syncPublisher(messageTopic).handle("hello world");

    // 模块级, 官方已经废弃这种消息
    Module module = null;
    module.getMessageBus().syncPublisher(messageTopic).handle("hello world");
}

主题中定义的传播方向决定着消息在总线中的传播情况,如果使用默认的TO_CHILDREN,则整个应用、项目、模块的消息总线上都会存在该主题。
消息广播案例

传播方向是: Application -> Project -> Module,此方向不可逆。

消费者

平台版本如何是2019.3之后,可以使用声明式注册来定义消费者。本文主要还是说说如何在代码中编写一个消费者吧。

  • 首先需要创建一个与消息总线的链接
  • 订阅某个主题
  • 实现MessageHandler
public void subscribe() {
    Application application = ApplicationManager.getApplication();
    application.getMessageBus().connect().subscribe(messageTopic, System.out::println);

    Project project = null;
    project.getMessageBus().connect().subscribe(messageTopic, System.out::println);

    Module module = null;
    module.getMessageBus().connect().subscribe(messageTopic, System.out::println);
}

有时候消费者收到消息需要对界面做出修改,生产者所在线程不属于Event线程,然后就会出现线程权限问题,目前可以使用以下代码来解决:

application.getMessageBus().connect()
    .subscribe(messageTopic, msg -> application.invokeLater(() -> System.out.println(msg)));

这个地方需要对IDEA的线程模型进行深入了解,官网对此有些许描写,具体内容还需要去看源码中的注释。

本文主要记录IDEA消息的简单用法,不对底层原理进行深入描述,更多内容可以查看官方文档或者源代码。

参见: Messaging InfrastructureMessaging Infrastructure

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注