8条经验轻松上手IDEA插件开发

简介: 本文从IDEA插件的基本概念讲起,通过一个简单的开发实例,介绍IDEA插件开发的过程,并总结了8条实战经验。更详细的IDEA插件开发介绍,可参见官方说明或到官方论坛讨论。

1.png

作者 | 冀泽
来源 | 阿里技术公众号

IDEA作为我们(后端Java开发者)必不可少的IDE,以其智能的代码提示、多样的框架支持、简洁的开发界面等特性,被业界公认为最好的Java开发工具之一。而一款IDE是否强大,最简单的衡量标准就是查看其插件生态环境的发展情况,多种多样的插件既丰富了IDE自身的功能,同时大大提高了开发人员的工作效率。

一 概念简介

插件类型

IDEA的插件根据功能分为以下4种类型:

  • 自定义语言支持,例如Go语言插件。这种插件包括文件类型识别、格式化、语言保留字支持、编译、运行等语言开发必备功能。属于比较重量级的插件。
  • 开发框架支持,例如Spring框架插件。这种插件包括框架特殊代码识别、框架功能支持等。不同开发框架开发量、难度不同。
  • 工具集成,例如我司内容的云雀,就是这种插件,也是最常用的插件,后续的开发实例也属于这种类型。这种插件一般包括额外的功能、功能相关的UI以及访问外部资源。
  • UI附加,主要限于UI的修改。

开发目录结构

2.png

组成部分

  • 配置文件,配置文件就是插件对IDE的自我介绍,IDEA中是META-INF/plugin.xml,详细的配置信息请参见官方文档。
  • ClassLoader,每个插件对应一个ClassLoader,彼此之间隔离(类似于Pandora的插件机制)。
  • Component(组件),插件内部可以有三个级别的组件:Applciation、Project、Module,分别需要在plugin.xml文件配置,并实现不同的接口。
  • 扩展和扩展点(Extesions and Extension Points),扩展用于扩展IDEA自身或者其他组件扩展点的功能,例如添加一个自定义的JavaDoc中的Tag。扩展点是插件提供给其他插件使用的。
  • 动作(Action),动作在配置文件中配置,由某个菜单项触发。
  • 图标(Icon),插件使用到的图标。
  • 服务(Service),用于后端运行的某些服务实现。
  • 依赖(Dependencies),插件可能依赖的其他插件、三方包等。

二 开发过程简述

此部分以一个简单插件开发实例进行说明。

1 创建项目

IDEA插件项目开发时,有两种创建方式,一种是IntelliJ Platform Plugin,另一种是Gradle下的IntelliJ Platform Plugin(在Gradle插件安装的情况下)。推荐使用第二种方式,使用Gradle的方式可以方便的添加第三方依赖库,同时也是官方推荐的方式。

选择好创建方式后,根据需要填写信息即可完成创建。

2 设置创建入口

由于实例插件是一个工具集成类型的插件,我们需要在IDEA的UI添加插件的入口,这部分在配置文件plugin.xml中添加如下内容:

<actions>
    <!-- Add your actions here -->
    <group id="分组id" text="显示文本1" description="鼠标驻留时的显示">
        <add-to-group group-id="MainMenu(这个id指的是IDEA的顶部菜单)" anchor="位置(last等)"/>
        <action class="动作类全路径" id="动作类id" text="显示文本2" description="鼠标驻留时的显示"/>
    </group>
</actions>

我们可以发现,入口就是一个Action。需要申明Action的位置和处理类。以上声明的UI效果:

3.png

3 编写处理逻辑

在配置文件中指明的动作处理类中添加处理逻辑。具体逻辑根据实际需要。

三 使用总结

1 弹出对话框

使用:
Messages.showErrorDialog(myTabbedPane.getComponent()," 弹出文本内容");

4.png

2 提示信息

使用 new Notification(groupId 自定义, 标题, 内容, 类型(info、warning、error)).notify(项目对象实例);

5.png

3 扩展点使用

在配置文件中,添加扩展点配置,其他扩展点类型:

<extensions defaultExtensionNs="com.intellij">
    <!-- 添加自定义扩展标签,这里的customJavadocTagProvider是IDEA自身申明的 -->
    <customJavadocTagProvider implementation="扩展点实现类"/>
</extensions>

自定义JavaDoc的扩展效果:

6.png

4 自定义LiveTemplate

(1)在plugin.xml中配置liveTemplate扩展点的相关实现:

<!-- 自定义LiveTemplate -->
<defaultLiveTemplatesProvider
    implementation="DefaultLiveTemplatesProvider接口的实现类"/>
<!-- 自定义LiveTemplate上下文,以及上下文可以使用的配置 -->
<liveTemplateContext
    implementation="TemplateContextType类的子类"/>

(2)在 DefaultLiveTemplatesProvider 接口的实现类的 getDefaultLiveTemplateFiles 方法中注册LiveTemplate定义文件:

@Override
public String[] getDefaultLiveTemplateFiles() {
    //文件名不需要有后缀,例如a.xml,这里只需要输入a
    return new String[]{"liveTemplates/文件1", "liveTemplates/文件2"};
}

(3)在 TemplateContextType 类的子类的构造方法中定义上下文名称,以及 isInContext 方法中定义上下文可以使用的位置。例如:

public XXXJavaInlineCommentContextType() {
    super("上下文id", "名称", 上下文基础类型);
}

@Override
public boolean isInContext(@NotNull final PsiFile file, final int offset) {
    if (PsiUtilCore.getLanguageAtOffset(file, offset).isKindOf(JavaLanguage.INSTANCE)) {
        PsiElement element = file.findElementAt(offset);
        if (element instanceof PsiWhiteSpace && offset > 0) {
            element = file.findElementAt(offset-1);
        }
        if (null == element) {
            return false;
        }
        return (element.getParent() instanceof PsiInlineDocTag && element.getParent().getParent() instanceof PsiDocTag)
            || (element.getParent() instanceof PsiInlineDocTag && PsiTreeUtil.getParentOfType(element, PsiField.class, false) != null);
    }
    return false;
}

(4)编写LiveTemplate定义xml文件,例如:

<templateSet group="分组名">
<template name="模板名" value="模板值,可以使用$VAR1$来指代变量位置" description="描述信息" toReformat="false" toShortenFQNames="true">
    <variable name="变量名" expression="" defaultValue="" alwaysStopAt="true" />
    <context>
        <option name="自定义的或者预定义的template上下文id" value="true" />
    </context>
</template>
</templateSet>

5 插件中调用Dubbo

(1)在Gradle的构建文件build.gradle中的dependencies内添加如下配置:

compile 'org.apache.dubbo:dubbo:2.7.7'
 compile 'org.apache.dubbo:dubbo-dependencies-zookeeper:2.7.7'

(2)在接口调用处进行如下编码:

//将当前线程的classloader备份,并设置当前线程的classloader为当前类的classloader
//当前线程的classloader是IDEA的,当前类的classloader是当前插件的
//不进行如此设置会造成Dubbo扩展点实现无法在ClassLoader中找到
ClassLoader backCl = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
// 以下内容参考Dubbo的泛化调用
// 当前应用配置
ApplicationConfig application = new ApplicationConfig();
application.setName("应用名");

// 连接注册中心配置
RegistryConfig registry = new RegistryConfig();
registry.setAddress("zookeeper://127.0.0.1:2181");

// 引用远程服务
ReferenceConfig<GenericService> reference = new ReferenceConfig<GenericService>(); // 此实例很重,封装了与注册中心的连接以及与提供者的连接,请自行缓存,否则可能造成内存和连接泄漏
reference.setApplication(application);
reference.setRegistry(registry); // 多个注册中心可以用setRegistries()
reference.setInterface("服务全类名");
reference.setVersion("服务版本号");
reference.setGeneric(true);

// 和本地bean一样使用xxxService
GenericService genericService = reference.get();
//泛化调用
Object result = genericService.$invoke("方法名", new String[]{"参数类型"}, new Object[]{"参数值"});
System.out.println(result);
//恢复classloader设置
Thread.currentThread().setContextClassLoader(backCl);

6 发布插件的指定IDEA仓库

(1)在build.gradle文件中进行如下配置

publishPlugin {
    host = 'https://xxxx.com'  //仓库地址
    username 'onepublish' //仓库指定用户名
    password 'onepublish' //仓库密码
    token 'onepublish'  //仓库验证token
}

(2)执行gradle中publishPlugin任务。

7 发布到指定IDEA插件失败

当我们开发完成后,通过publishPlugin任务发布时,可能会出现以下报错信息:

The resource identified by this request is only capable of generating responses with characteristics not acceptable according to the request "accept" headers.

这个问题的原因是我们使用的org.jetbrains.intellij版本较高,请使用2.x的版本。或者参照插件的源码自己写一个没有accept的上传方法即可。

相关代码:

package idea;

import retrofit.RestAdapter;
import retrofit.client.Request;
import retrofit.client.Response;
import retrofit.client.UrlConnectionClient;
import retrofit.converter.SimpleXMLConverter;
import retrofit.mime.TypedFile;
import retrofit.mime.TypedString;

import java.io.File;
import java.io.IOException;
import java.net.HttpURLConnection;

/**
 * @author lijie
 * @date 2019/1/17
 */
public class PublishPluginTest {
    public static void main(String[] args) {
        PluginRepositoryService service = new RestAdapter.Builder().setEndpoint("https://插件仓库链接").setClient(new UrlConnectionClient() {
            @Override
            protected HttpURLConnection openConnection(Request request) throws IOException {
                HttpURLConnection connection = super.openConnection(request);
                connection.setReadTimeout(10 * 60 * 1000);
                return connection;
            }
        }).setLogLevel(RestAdapter.LogLevel.BASIC)
            .setConverter(new SimpleXMLConverter())
            .build()
            .create(PluginRepositoryService.class);
        Response response = service.uploadByXmlId(new TypedString(""), new TypedString(""),
            new TypedString(pluginId), new TypedString("default"),
            new TypedFile("application/octet-stream",
                new File(plugin压缩文件路径)));
        System.out.println(response.getBody());
    }
}
package idea;

import retrofit.client.Response;
import retrofit.http.*;
import retrofit.mime.TypedFile;
import retrofit.mime.TypedString;

/**
 * @author lijie 
 * @date 2019/1/17
 */
public interface PluginRepositoryService {
    @Multipart
    @POST("/plugin/uploadPlugin")
    public Response uploadByXmlId(@Part("userName")TypedString username, @Part("password")TypedString password,
                                  @Part("pluginId")TypedString pluginId, @Part("channel")TypedString channel,
                                  @Part("file")TypedFile file);
}

8 如何在插件中引入本地jar包

在build.gradle的dependencies里边添加如下内容:

compile fileTree(dir:'src/main/resources/lib',includes:['*jar'])

然后,将本地jar包放到指定目录即可。

相关文章
|
2月前
|
网络协议 Windows
两步带你解决IDEA 插件下载安装慢、超时、不成功问题
这篇文章提供了解决IDEA插件下载慢或超时问题的方案,通过查找国内插件节点IP地址并修改本地hosts文件来加速下载。
两步带你解决IDEA 插件下载安装慢、超时、不成功问题
|
6天前
|
Java
轻松上手Java字节码编辑:IDEA插件VisualClassBytes全方位解析
本插件VisualClassBytes可修改class字节码,包括class信息、字段信息、内部类,常量池和方法等。
47 6
|
2月前
|
Java
可直接编辑jar包的IDEA插件-JarEditor
IDEA自带的反编译插件虽可查看jar包中的class文件,但无法直接编辑。为解决此问题,作者开发了JarEditor插件,可在IDEA中直接编辑jar文件内的class及资源文件,无需解压或手动编译。点击Jar Editor可修改代码,通过Save/Compile保存并编译,Build Jar则将更改写回jar包。该插件简化了jar包编辑流程,提高了开发效率。
185 4
可直接编辑jar包的IDEA插件-JarEditor
|
4月前
|
IDE 程序员 开发工具
IDEA插件-IKun Progress 坤坤成IDEA进度条了
"IKun Progress"是一款适用于JetBrains IntelliJ IDEA等IDE的插件,该插件能够将标准的进度条替换为一个有趣且独特的篮球动画,其中的角色名为坤坤(Kun Kun)。它旨在为您的IDE使用过程增添一些娱乐和轻松的氛围。 该插件让您可以在执行IDE中的任务时享受到更加视觉上吸引人的进度指示器,例如构建、运行测试或其他涉及进度条的操作。相比传统的普通进度条,您将看到坤坤在打篮球,给您的开发工作流程增添了一份乐趣。
693 0
IDEA插件-IKun Progress 坤坤成IDEA进度条了
|
1月前
|
Windows
IDEA如何查看已经安装的插件并删除
【10月更文挑战第1天】这段内容主要介绍了如何在IntelliJ IDEA中查看和删除已安装的插件。可以通过软件内的插件市场查看插件列表,包括插件名称、版本号和供应商等信息;也可以通过访问插件目录查看。删除插件则建议在插件市场中进行,包括禁用和卸载步骤,手动删除插件文件夹的方法不推荐,因为可能存在配置残留等问题。
487 11
|
1月前
|
人工智能 Java 数据库连接
IDEA开发 常用代码规范插件 常用辅助类插件
IDEA开发 常用代码规范插件 常用辅助类插件
45 0
|
1月前
|
IDE Java Maven
分享几个实用的IDEA插件,提高你的工作效率!
分享几个实用的IDEA插件,提高你的工作效率!
130 0
|
3月前
|
自然语言处理 JavaScript 算法
【插件】IDEA这款插件,爱到无法自拔
本文介绍了阿里云「通义灵码」这一强大IDEA插件,它不仅能够智能生成代码、解答研发问题,还支持多种编程语言和编辑器。文章详细展示了如何安装使用该插件,并通过多个实际案例说明其在代码解释、优化、生成注释及单元测试等方面的应用,助力开发者提高效率。强烈推荐尝试!
119 1
【插件】IDEA这款插件,爱到无法自拔
|
3月前
|
Java
2022年最新最详细的IntelliJ idea高效插件的介绍安装,让你的工作效率提升10倍
这篇文章详细介绍了10款IntelliJ IDEA的高效插件,包括Codota代码智能提示、Key Promoter X快捷键提示、CodeGlance代码缩略图、Lombok代码简化、阿里巴巴代码规范检查、SonarLint代码质量检查、Save Actions格式化代码、Translation翻译、Rainbow Brackets彩虹括号和Nyan Progress Bar彩虹进度条插件,旨在帮助提升开发效率和代码质量。
2022年最新最详细的IntelliJ idea高效插件的介绍安装,让你的工作效率提升10倍
|
4月前
|
Java
[JarEditor]可直接修改jar包的IDEA插件
### 修改JAR包变得更简单:JarEditor插件简介 **背景:** 开发中常需修改JAR包中的class文件,传统方法耗时费力。JarEditor插件让你一键编辑JAR包内文件,无需解压。 **插件使用:** 1. **安装:** 在IDEA插件市场搜索JarEditor并安装。 2. **修改class:** 打开JAR文件中的class,直接编辑,保存后一键构建更新JAR。 3. **文件管理:** 右键菜单支持在JAR内新增/删除/重命名文件等操作。 4. **搜索:** 使用内置搜索功能快速定位JAR包内的字符串。
457 2
[JarEditor]可直接修改jar包的IDEA插件