插件是扩展IDEA功能的唯一途径。一款插件使用IDEA或其他插件暴露的API实现它的功能。这篇文章关注插件系统的结构和插件的生命周期。文章中不会指出任何可能被插件使用的其他API接口。
文章中包含了以下主题:
有3种方式组织插件内容:
1.由插件文件夹内的一个.jar文件构成一个插件。这个压缩包内应该包含配置文件(META-INF/plugin.xml)和实现插件功能的类文件。配置文件指出插件的名称、描述、版本、厂商(制作者)、支持的IDEA版本、插件组件、交互(Action)和交互组(Action Group)、Action用户界面位置等。
.IntelliJIDEAx0
plugins
sample.jar/
com/foo/.....
...
...
META-INF
plugin.xml
2.插件文件位于一个文件夹中:
.IntelliJIDEAx0
plugins
Sample
lib
libfoo.jar
libbar.jar
classes
com/foo/....
...
...
META-INF
plugin.xml
“classes”文件和所有“lib”文件夹下的jar包会被自动加入classpath中。
3.插件文件位于lib文件夹下的一个jar文件中:
.IntelliJIDEAx0
plugins
Sample
lib
libfoo.jar
libbar.jar
Sample.jar/
com/foo/.....
...
...
META-INF
plugin.xml
所有来自lib文件夹下的jar包会被自动加入classpath中。
为了加载各个插件的类文件,IDEA使用一个单独的类加载器。这允许各个插件使用同一类库的不同版本,即使相同的类库被IDEA或另一个插件使用。
默认情况下,IDEA的主要类加载器加载那些插件类加载器找不到的类。然而,在plugin.xml文件中,可以使用
组件是插件整合的基础概念。有三种组件类型:application-level、project-level和module-level。
Application-level组件在IDEA启动时就被创建并初始化。可以从Application实例中使用getComponent(Class)方法来获取它们。
Project-level组件被IDEA中的各个Project实例创建(请注意组件甚至可以被未打开的project创建)。可以从Project实例中使用getComponent(Class)方法来获取它们。
Module-level组件在IDEA加载各个project时为各个Module创建。Module-level组件可以从Module实例中使用相同的方法获得。
各个组件都应在配置文件中指明接口和实现类。接口类用于从其他组件索引组件(附原文,水平有限,实在不知道怎么翻译:The interface class will be used for retrieving the component from other components),实现类用于组件实例化。注意两个同水平(Application、Project或Module)的两个组件不能使用相同的接口类。接口和实现类可以相同。
每个组件具有唯一的名称用于外部和内部的需求。组件名称可由它的getComponentName()方法返回。
推荐以
Application-level组件实现类可以选择性的实现ApplicationComponent接口。一个无依赖的application组件应该有一个无参数的构造器用于组件实例化。如果一个application组件依赖于其他application组件,它应该指定这些组件作为构造器的参数,那么IDEA将会保证这些组件按正确的顺序实例化以保证依赖关系。
注意application-level组件必须在plugin.xml文件中在
IntelliJ IDEA建议通过一种简化的方式创建application组件,具有所有需要的基础结构。IDEA的接口将帮助你声明一个application组件实现类并自动在plugin.xml文件的
要创建并注册一个application组件:
IntelliJ IDEA生成一个实现ApplicationComponent接口的一个Java类,在plugin.xml文件中注册新创建的组件,在模块树视图中增加一个节点,并在编辑器中打开创建的application组件类文件。
Project-level组件的实现类可以实现ProjectComponent接口。一个project-level组件的构造器可以包含一个Project类型的参数,如果它需要一个project实例。还可以指定其他application-level或project-level组件作为参数,如果它依赖这些组件。
注意project-level组件必须在plugin.xml文件的
IntelliJ IDEA建议通过一种简化的方式创建project组件,具有所有需要的基础结构。IDEA的接口可以帮助你声明一个project组件的实现类并自动在plugin.xml文件的
要创建并注册一个project组件
IntelliJ IDEA生成一个实现ProjectComponent接口的一个Java类,在plugin.xml文件中注册新创建的组件,在模块树视图中增加一个节点,并在编辑器中打开创建的project组件类文件。
Module-level组件实现类可以选择性的实现ModuleComponent接口。一个module-level组件的构造器可以包含一个Module类型的参数,如果它需要一个module实例。还可以指定其他application-level、project-level或者module-level组件作为参数,如果它依赖这些组件。
注意module-level组件必须在plugin.xml文件的
IntelliJ IDEA建议通过一种简化的方式创建module组件,具有所有需要的基础结构。IDEA的接口可以帮助你声明一个module组件的实现类并自动在plugin.xml文件的
要创建并注册一个module组件
IntelliJ IDEA生成一个实现ModuleComponent接口的一个Java类,在plugin.xml文件中注册新创建的组件,在模块树视图中增加一个节点,并在编辑器中打开创建的module组件类文件。
如果组件的实现类实现了JDOMExternalizable(已过时)接口或PersistentStateComponent接口,组件的状态会被自动保存和加载。
当组件的类实现了PersistentStateComponent接口时,组件的状态(你可以在Java代码中使用@State和@Storage注释指定)保存到一个XML文件中。
当组件的类实现了JDOMExternalizable接口时,组件在如下文件中保存状态:
要获取更多信息和例子,可以参考Persisting State of Components。
默认值(组件的预定义设置)应该在
组件将按如下顺序加载:
组件将按如下顺序卸载:
注意,在你的组件的构造器中,你不能使用getComponent()方法来请求其他组件,否则,你将得到一个断言(get an assertion)。如果你需要在初始化组件时访问其他组件,你可以将它们指定为构造器参数或者在initComponent方法中访问它们。
一个阐述如何创建具有application level和project level组件的插件的示例插件可以在<%IDEA project directory%>/community/samples/plugin文件夹下得到。
要打开示例插件
Intellij IDEA提供扩展和扩展点的概念,允许一款插件和另一款插件或IDEA内核进行互动。
如果你希望你的插件允许其他插件扩展它的功能,在这个插件中,你必须声明一个或多外扩展点。每一个扩展点定义允许访问这个扩展点的一个类或接口。
如果你希望你的插件扩展其他插件或IDEA内核的功能点,在这个插件中,你必须声明一个或多个扩展。
你可以在插件的配置文件plugin.xml里
为了澄清此步骤,参考如下plugin.xml文件示例小节:
interface属性设定一个有助于此扩展点的插件必须实现的接口。(翻译的感觉不太对,附原文:The interface attribute sets an interfacethe plugin that contributes to the extension point must implement. 原文中的第二个“the”,感觉怎么翻译都不对味。)
beanClass属性设定一个声明了具有一个或多个被“@Attribute”标注注释的属性的bean类。有助于此扩展点的插件将从plugin.xml中读取这些属性(附原文:The plugin that contributes to the extension point will read those properties from the plugin.xml file.)。为了阐述此配置,参考如下示例代码:上述plugin.xml文件配置使用中的MyBeanClass1 bean类:
public class MyBeanClass1 extends AbstractExtensionPointBean {
@Attribute("key")
public String key;
@Attribute("implementationClass")
public String implementationClass;
public String getKey() {
return key;
}
public String getClass() {
return implementationClass;
}
}
注意为了声明一个设计要连接到MyExtensionPoint1扩展点的扩展,你的plugin.xml文件中必须包含具有“key”和“implementationClass”属性的
为了阐述这个过程,参考如下plugin.xml文件示例片段,其中定义了:两个分别设计要访问IDEA内核中定义的appStarter和applicationConfigurable扩展点的扩展、一个要访问在一个测试插件中定义的MyExtensionPoint1扩展点的扩展:
要获得可在IntelliJ IDEA内核访问的扩展点列表,参阅如下XML配置文件的
要获取示例插件和关于如何创建贡献IDEA内核扩展的插件的详细介绍,参考Customizing the IDEA Settings Dialog和Creation of Tool Windows.
Intellij IDEA提供交互(action)的概念。一个交互是一个源于AnAction类的子类,其actionPerformed方法将在菜单项或工具栏按钮被选中时调用。交互系统允许插件向IDEA菜单和工具栏中增加自己的菜单/工具项。
交互被按组管理,一个组可以包含其他的组。一组交互可以形成一个工具栏或菜单。组的子组可以构成菜单的子菜单。
你可以从IntelliJ IDEA Action System和Creating an Action找到如何创建并注册交互的详细信息。
IntelliJ IDEA提供服务的概念。一个服务是一个在你的插件调用ServiceManager类的getService方法时按需加载的插件组件。即使一个服务被请求多次,IntelliJ IDEA也保证每个服务只有一个实例被加载。一个服务必须在plugin.xml文件中指明接口和实现类。
服务的实现类用于服务的实例化。
IntelliJ IDEA提供3类服务:application服务、project服务和module服务。
要声明一个服务,你可以使用如下IDEA内核的扩展点:
要声明一个服务
注意接口和实现类可以是同一个类。
为了阐述服务声明过程,参考如下的plugin.xml框架:
为了实例化你的服务,在Java代码中,使用如下语法:
MyServiceImplClass service = ServiceManager.getService(MyServiceImplClass.class);
这个小节将允许你下载并安装一个说明如何创建并使用一个插件服务的示例插件。
这个插件拥有一个实现了一个服务的project组件,这个服务统计当前IntelliJ IDEA打开的project数量。如果这个统计数超出了允许同时打开project的最大数的限制,这个插件将返回一个错误信息并关闭最近打开的project。
要安装并运行示例插件
如下是一份示例插件配置文件。此示例展示并描述了所有会在plugin.xml文件中使用的元素。
VssIntegration
VssIntegration
Vss integration plugin
Initial release of the plugin.
1.0
Foo Inc.
MyFirstPlugin
MySecondPlugin
messages.MyPluginBundle
com.foo.Component1Interface
com.foo.impl.Component1Impl
com.foo.Component2
com.foo.Component3
原文未完成(work in progress) 2014/11/14 link:http://confluence.jetbrains.com/display/IDEADEV/IntelliJ+IDEA+Plugin+Structure