1、插件內的文件
2、插件類加載器
3、插件組件(component)
4、插件的擴展以及擴展點(Extensions、Extension Points)
5、插件的Action
6、插件的Service
7、插件配置文件結構
8、插件依賴
插件內的文件
有兩種方式組織你的插件目錄內的文件。
1、插件相關的 jar 文件放在插件根目錄下
2、jar 文件放在 lib 文件夾下
如下:實際上,大部分都是插件目錄下放個lib文件夾,把插件放到 lib 下。
我們通過 idea 的 build 菜單的 "prepare plugin moudle xxx for deployment" 生成的插件文件內,解壓也是一個 lib 文件夾,里面放插件。
除此之外,plugin.xml 文件應該放在 META-INF 文件夾下保存。
插件類加載器
每一個插件都可以有一個獨立的類加載器,這樣的好處是,允許不同插件可以使用不同版本的庫。
默認情況下,插件不會使用 IDE 的類加載器,所以 plugin.xml 中的 depends 的 <depends>com.intellij.modules.platform</depends> 如果不加上去,插件打包之后並不會生效。
你也可以使用 <depends> 元素來指定一個或多個當前插件所依賴的插件,這樣一來,我們就可以在當前插件使用其他插件的類加載器,這樣我們就可以引用其他插件里面定義的類。
插件組件
插件組件是插件集成的基礎概念,有三種組件:
1、應用級組件(Application level components):IDE 啟動的時候會創建和初始化。我們可以通過 Application 實例來獲取這些組件。(通過 ApplicationManager獲取Application實例,application.getComponent(Class))
2、項目級組件(Project level components):該類組件為每個 Project 實例創建。我們可以通個 Project 實例來獲取這些組件。(通過 Project project = anActionEvent.getData(PlatformDataKeys.PROJECT); 獲取 Project 實例,project.getComponent(Class))
3、模塊級組件(Module level components):該類組件為每個 project 的 Moudule 創建。我們可以通過 Module 實例來獲取這些組件。
我們插件定義的每一個組件(component) 應該在配置文件中配置相關的接口(可選)和實現類,如下:
<application-components> <component> <implementation-class>com.eleven24.HelloWorldRegistration</implementation-class> </component> </application-components>
配置的實現類將會被用於組件實例化。
兩個相同級的組件不能有相同的接口類。
每個組件有一個唯一的名字用來作為外部標識或者內部需要,通過組件的 getComponentName() 返回:
public class HelloWorldRegistration implements ApplicationComponent { @NotNull public String getComponentName() { return "HelloWorldPlugin"; } }
組件命名
推薦使用 <plugin_name>.<component_name> 的方式命名。
應用級組件
一個應用級的組件實現類可以選擇是否去實現 ApplicationComponent 接口。
一個沒有任何依賴的組件應該有一個空參數的構造方法用以實例化。如果組件依賴其他組件,可以在構造方法參數中指定依賴的組件。IntelliJ Platform 會確保以正確的順序來實例化組件,以保證我們組件可以正確實例化。
應用級組件必須在 plugin.xml 的 <application-components> 塊中注冊。
項目級組件
一個 Project 級的組件可以選擇是否去實現 ProjectComponent 接口。
一個 project 級的組件如果需要 Project 實例,可以在該組件類的構造方法中指定一個 Project 類型的參數。同時如果依賴其他組件也可以指定其他 Application level 或者 Project level 的組件作為構造方法參數。
project 級組件必須在 plugin.xml 的 <project-components> 塊中注冊。
模塊級組件
一個 Module 級的組件可以選擇是否去實現 ModuleComponent 接口。
一個 Module 級組件可以在構造方法指定一個 Module 類型的參數。同時如果依賴其他組件,也可以指定 application level、projetc level 或 module level 組件作為參數。
module 級組件必須在 plugin.xml 的 <module-components> 塊中注冊。
組件狀態的持久化
如果組件類實現了 JDOMExternalizable 或者 PersistentStateComponent 接口,組件的狀態將會自動保存和加載。
當組件類實現了 PersistentStateComponent 接口,組件狀態會保存在一個 xml 文件中,你可以通過 @State 和 @Storage 注解來指明當前的狀態。
當組件實現了 JDOMExternalizable 接口,組件將會在下面的文件中保存它們的狀態:
- project 級的組件的狀態會保存在 .ipr 文件中,如果 plugin.xml 的 workspace 選項被設置為 true,將會被保存在 .iws 文件而不是 .ipr 文件中。
- module 級的組件狀態將會保存在 .iml 文件中
更多信息可查看:Persisting State of Components
插件默認配置
定義在 <component_name>.xml 文件中,該文件需要放在 默認 package 的 classpath 下。
如果插件有默認配置,readExternal() 將會被調用兩次:
1、第一次讀取默認配置
2、第二次讀取保存的配置
插件組件生命周期
組件按下面的順序加載:
1、創建 - 構造方法被調用
2、初始化 - initComponent 方法被調用(前提是實現了 ApplicationComponent 接口)
3、配置 - readExternal 方法被調用(前提是實現了 JDOMExternalizable 接口),或者 loadState 被調用 (組件實現了 PersistentStateComponent 接口)
4、對於 module 組件, 如果一個模塊被添加到 project, ModuleComponent 接口的 moduleAdded 方法將會被調用。
5、對於 project 組件,如果一個 project 被加載完, ProjectComponent 接口的 projectOpened 方法將會被調用。
組件按下面的順序卸載:
1、保存配置 - writeExternal 被調用(如果該組件實現了 JDOMExternalizable 接口),getState 被調用(如果組件實現了 PersistentStateComponent 接口)
2、清理 - 組件的 disposeComponent 方法被調用
注意,不能在組件的構造方法中使用 getComponent() 方法去獲取其他組件,如果你需要獲取其他組件,可以將它們加到構造方法的參數中,或者在 initComponent 方法再進行此種操作。
todo: 添加例子
插件的擴展以及擴展點
Intellij 平台提供了允許一個插件與其他插件或者 IDE 交互的 extensions 以及 extension points 的概念。
extension points
如果你想要你的插件可以被其他插件使用,那么你必須在你的插件內聲明一個或多個擴展點(extension points)。每個擴展點定義了允許訪問這個點的類或者接口。
extensions
如果你想要你的插件擴展其他插件或者 Intellij 平台,你必須聲明一個或多個 extensions
怎樣聲明 extensions 以及 extension points
你可以在你的 plugin.xml 中的 <extensions> 和 <extensionPoints> 塊中定義 extensions 以及 extension points。
定義一個 extension point