标签:intellij idea 插件 结构 扩展 框架
插件是扩展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文件中,可以使用<depends>元素来指定一个插件依赖于另一个或更多其他插件。在这种情况下,那些(被依赖的)插件的类加载器将(优先)用来加载当前插件的类加载器找不到的类。这将允许一个插件引用另一个插件中的类。
组件是插件整合的基础概念。有三种组件类型: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()方法返回。
推荐以<plugin_name>.<component_name>格式命名组件。
Application-level组件实现类可以选择性的实现ApplicationComponent接口。一个无依赖的application组件应该有一个无参数的构造器用于组件实例化。如果一个application组件依赖于其他application组件,它应该指定这些组件作为构造器的参数,那么IDEA将会保证这些组件按正确的顺序实例化以保证依赖关系。
注意application-level组件必须在plugin.xml文件中在<application-components>小节中注册(参见之后的组件配置文件小节)。
IntelliJ IDEA建议通过一种简化的方式创建application组件,具有所有需要的基础结构。IDEA的接口将帮助你声明一个application组件实现类并自动在plugin.xml文件的<application-components>小节进行适当的修改。
要创建并注册一个application组件:
IntelliJ IDEA生成一个实现ApplicationComponent接口的一个Java类,在plugin.xml文件中注册新创建的组件,在模块树视图中增加一个节点,并在编辑器中打开创建的application组件类文件。
Project-level组件的实现类可以实现ProjectComponent接口。一个project-level组件的构造器可以包含一个Project类型的参数,如果它需要一个project实例。还可以指定其他application-level或project-level组件作为参数,如果它依赖这些组件。
注意project-level组件必须在plugin.xml文件的<project-components>小节中注册(参见之后的组件配置文件小节)。
IntelliJ IDEA建议通过一种简化的方式创建project组件,具有所有需要的基础结构。IDEA的接口可以帮助你声明一个project组件的实现类并自动在plugin.xml文件的<project-components>小节进行适当的修改。
要创建并注册一个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文件的<module-components>小节中注册(参见之后的组件配置文件小节)。
IntelliJ IDEA建议通过一种简化的方式创建module组件,具有所有需要的基础结构。IDEA的接口可以帮助你声明一个module组件的实现类并自动在plugin.xml文件的<module-components>小节进行适当的修改。
要创建并注册一个module组件
IntelliJ IDEA生成一个实现ModuleComponent接口的一个Java类,在plugin.xml文件中注册新创建的组件,在模块树视图中增加一个节点,并在编辑器中打开创建的module组件类文件。
如果组件的实现类实现了JDOMExternalizable(已过时)接口或PersistentStateComponent接口,组件的状态会被自动保存和加载。
当组件的类实现了PersistentStateComponent接口时,组件的状态(你可以在Java代码中使用@State和@Storage注释指定)保存到一个XML文件中。
当组件的类实现了JDOMExternalizable接口时,组件在如下文件中保存状态:
要获取更多信息和例子,可以参考Persisting State of Components。
默认值(组件的预定义设置)应该在<component_name>.xml文件中设置。将这个文件放到插件的classpath中与默认包路径对应的文件夹中。readExternal()方法将在<component>根标签处理被调用。如果一个组件有默认值,readExternal()方法将被调用两次:第一次用来读取默认值,第二次用于保存配置(应该是用来对比是否相对默认值做了更改)。
组件将按如下顺序加载:
组件将按如下顺序卸载:
注意,在你的组件的构造器中,你不能使用getComponent()方法来请求其他组件,否则,你将得到一个断言(get an assertion)。如果你需要在初始化组件时访问其他组件,你可以将它们指定为构造器参数或者在initComponent方法中访问它们。
一个阐述如何创建具有application level和project level组件的插件的示例插件可以在<%IDEA project directory%>/community/samples/plugin文件夹下得到。
要打开示例插件
Intellij IDEA提供扩展和扩展点的概念,允许一款插件和另一款插件或IDEA内核进行互动。
如果你希望你的插件允许其他插件扩展它的功能,在这个插件中,你必须声明一个或多外扩展点。每一个扩展点定义允许访问这个扩展点的一个类或接口。
如果你希望你的插件扩展其他插件或IDEA内核的功能点,在这个插件中,你必须声明一个或多个扩展。
你可以在插件的配置文件plugin.xml里<extensions> and <extensionPoints>小节的分别声明扩展和扩展点。
为了澄清此步骤,参考如下plugin.xml文件示例小节:
<extensionPoints> <extensionPoint name="MyExtensionPoint1" beanClass="MyPlugin.MyBeanClass1"> <extensionPoint name="MyExtensionPoint2" interface="MyPlugin.MyInterface"> </extensionPoints>
interface属性设定一个有助于此扩展点的插件必须实现的接口。(翻译的感觉不太对,附原文:The interface attribute sets an interface
the 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”属性的<MyExtensionPoint1>标记来提供适当的值。(参见之后的plugin.xml)
为了阐述这个过程,参考如下plugin.xml文件示例片段,其中定义了:两个分别设计要访问IDEA内核中定义的appStarter和applicationConfigurable扩展点的扩展、一个要访问在一个测试插件中定义的MyExtensionPoint1扩展点的扩展:
<!-- Declare extensions to access extension points in the IDEA core. These extension points have been declared using the "interface" attribute. --> <extensions defaultExtensionNs="com.intellij"> <appStarter implementation="MyTestPackage.MyTestExtension1"></appStarter> <applicationConfigurable implementation="MyTestPackage.MyTestExtension2"></applicationConfigurable> </extensions> <!-- Declare extensions to access extension points in a custom plugin The MyExtensionPoint1 extension point has been declared using *beanClass* attribute. --> <extensions defaultExtensionNs="MyPluginID"> <MyExtensionPoint1 key="keyValue" implementationClass="MyTestPackage.MyClassImpl"></MyExtensionPoint1> </extensions>
要获得可在IntelliJ IDEA内核访问的扩展点列表,参阅如下XML配置文件的<extensionPoints>小节:
要获取示例插件和关于如何创建贡献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框架:
<extensions defaultExtensionNs="com.intellij"> <!-- Declare the application level service --> <applicationService serviceInterface="Mypackage.MyServiceInterfaceClass" serviceImplementation="Mypackage.MyServiceImplClass"> </applicationService> <!-- Declare the project level service --> <projectService serviceInterface="Mypackage.MyProjectServiceInterfaceClass" serviceImplementation="Mypackage.MyProjectServiceImplClass"> </projectService> </extensions>
为了实例化你的服务,在Java代码中,使用如下语法:
MyServiceImplClass service = ServiceManager.getService(MyServiceImplClass.class);
这个小节将允许你下载并安装一个说明如何创建并使用一个插件服务的示例插件。
这个插件拥有一个实现了一个服务的project组件,这个服务统计当前IntelliJ IDEA打开的project数量。如果这个统计数超出了允许同时打开project的最大数的限制,这个插件将返回一个错误信息并关闭最近打开的project。
要安装并运行示例插件
如下是一份示例插件配置文件。此示例展示并描述了所有会在plugin.xml文件中使用的元素。
<!-- url="" specifies the URL of the plugin homepage (displayed in the Welcome Screen and in "Plugins" settings dialog) --> <idea-plugin url="http://www.jetbrains.com/idea"> <!-- Plugin name --> <name>VssIntegration</name> <!-- Unique identifier of the plugin. Cannot be changed between the plugin versions. If not specified, assumed to be equal to <name>. --> <id>VssIntegration</id> <!-- Description of the plugin. --> <description>Vss integration plugin</description> <!-- Description of changes in the latest version of the plugin. Displayed in the "Plugins" settings dialog and in the plugin repository Web interface. --> <change-notes>Initial release of the plugin.</change-notes> <!-- Plugin version --> <version>1.0</version> <!-- The vendor of the plugin. The optional "url" attribute specifies the URL of the vendor homepage. The optional "email" attribute specifies the e-mail address of the vendor. The optional "logo" attribute specifies the path within the plugin JAR to a 16x16 icon to be displayed next to the plugin name in the welcome screen. --> <vendor url="http://www.jetbrains.com" email="support@jetbrains.com" logo="icons/plugin.png">Foo Inc.</vendor> <!-- The unique identifiers of the plugins on which this plugin depends. --> <depends>MyFirstPlugin</depends> <!-- Optional dependency on another plugin. If the plugin with the "MySecondPlugin" ID is installed, the contents of mysecondplugin.xml (the format of this file conforms to the format of plugin.xml) will be loaded. --> <depends optional="true" config-file="mysecondplugin.xml">MySecondPlugin</depends> <!-- Allows a plugin to integrate its help system (in JavaHelp format) with the IDEA help system. The "file" attribute specifies the name of the JAR file in the "help" subdirectory of the plugin directory. The "path" attribute specifies the name of the helpset file within the JAR file.--> <helpset file="myhelp.jar" path="/Help.hs" /> <!-- Minimum and maximum build of IDEA compatible with the plugin --> <idea-version since-build="3000" until-build="3999"/> <!-- Resource bundle from which the text of plugin descriptions, action names and etc. will be loaded --> <resource-bundle>messages.MyPluginBundle</resource-bundle> <!-- Plugin‘s application components --> <application-components> <component> <!-- Component‘s interface class --> <interface-class>com.foo.Component1Interface</interface-class> <!-- Component‘s implementation class --> <implementation-class>com.foo.impl.Component1Impl</implementation-class> </component> </application-components> <!-- Plugin‘s project components --> <project-components> <component> <!-- Interface and implementation classes are the same --> <interface-class>com.foo.Component2</interface-class> <!-- If the "workspace" option is set "true", the component saves its state to the .iws file instead of the .ipr file. Note that the <option> element is used only if the component implements the JDOMExternalizable interface. Otherwise, the use of the <option> element takes no effect. --> <option name="workspace" value="true" /> <!-- If the "loadForDefaultProject" tag is present, the project component is instantiated also for the default project. --> <loadForDefaultProject> </component> </project-components> <!-- Plugin‘s module components --> <module-components> <component> <interface-class>com.foo.Component3</interface-class> </component> </module-components> <!-- Actions --> <actions> <action id="VssIntegration.GarbageCollection" class="com.foo.impl.CollectGarbage" text="Collect _Garbage" description="Run garbage collector"> <keyboard-shortcut first-keystroke="control alt G" second-keystroke="C" keymap="$default"/> </action> </actions> <!-- Extension points defined by the plugin. Extension points are registered by a plugin so that other plugins can provide this plugin with certain data. The "beanClass" attribute specifies the class the implementations of which can be used for the extension point. --> <extensionPoints> <extensionPoint name="testExtensionPoint" beanClass="com.foo.impl.MyExtensionBean"/> </extensionPoints> <!-- Extensions which the plugin adds to extension points defined by the IDEA core or by other plugins. The "defaultExtensionNs " attribute must be set to the ID of the plugin defining the extension point, or to "com.intellij" if the extension point is defined by the IDEA core. The name of the tag within the <extensions> tag matches the name of the extension point, and the "implementation" class specifies the name of the class added to the extension point. --> <extensions xmlns="VssIntegration"> <testExtensionPoint implementation="com.foo.impl.MyExtensionImpl"/> </extensions> </idea-plugin>
原文未完成(work in progress) 2014/11/14 link:http://confluence.jetbrains.com/display/IDEADEV/IntelliJ+IDEA+Plugin+Structure
标签:intellij idea 插件 结构 扩展 框架
原文地址:http://blog.csdn.net/hawkdowen/article/details/41213001