动态插件
动态插件
从 2020.1版本开始,安装,更新,卸载插件都不需要再重启idea了
开发插件的时候,Auto-Reload 功能支持动态更新项目,
如果插件安装以后需要用户必须重启项目,需要在plugin.xml里配置 require-restart=true:
<idea-plugin require-restart="true">
</idea-plugin>
限制条件
支持 Auto-Reload功能的插件需要满足下面的条件:
不使用Components
如果使用了Components,可以参考 组件 更换为 使用services, extensions, or listeners 来实现相同功能
只能使用动态扩展点
直接使用的和间接使用的(依赖插件所使用的) 扩展点和监听器(Extension Point and Listener List ) 必须都是动态的
自己定义的扩展点也必须是动态的
如果自己定义了扩展点,扩展点也必须设置 dynamic="true",
<extensionPoints>
<extensionPoint
name="myDynamicExtensionPoint"
beanClass="com.example.MyBeanClass"
dynamic="true"/>
</extensionPoints>
依赖的扩展点的配置
依赖其它扩展点的类,必须实现Configurable.WithEpDependencies 接口
服务不能支持重写
使用的服务 不能设置 overrides="true"
提示
如果需要本地验证插件是否满足以上条件,可以使用 intellij-plugin-verifier 进行验证
代码
缓存
在加载和卸载插件的时候使用 CachedValuesManager清空所有缓存
不能保存 PSI(Program Structure Interface)
加载和卸载插件的时候,不能保存PSI element, 建议使用 SmartPsiElementPointer
不要使用 FileType/Language
使用string 替换 Language.getID()/FileType.getName()
加载/卸载事件
注册 应用监听器 DynamicPluginListener 来监听插件的加载/卸载事件
这也可以被用于,例如取消长时间运行的活动,或由于某个进程正在进行而禁止卸载。
故障排除
卸载或更新插件时,IDE 会同步等待插件卸载完成,如果卸载失败,则请求重新启动IDE,
使用最新版本的IDE排查故障,可以在 issues 查找相关问题
日志
事件类的相关日志都用 com.intellij.ide.plugins.DynamicPlugins 记录
内存泄漏
通过以下几步排查:
- 验证是否在build(build.gradle.kts或 build.gradle)文件中设置了 -XX:+UnlockDiagnosticVMOptions
- 设置 Registry key ide.plugins.snapshot.on.unload.fail = true
重新加载插件
打开 .hprof 内存快照文件 (idea可以直接打开)
查找带插件id的 PluginClassLoader
查看对 PluginClassLoader 实例的引用
日志参考如下
2020-12-26 14:43:24,563 [ 251086] INFO - lij.ide.plugins.DynamicPlugins - Snapshot analysis result: Root 1:
ROOT: Global JNI
sun.awt.X11.XInputMethod.clientComponentWindow
com.intellij.openapi.wm.impl.IdeFrameImpl.rootPane
com.intellij.openapi.wm.impl.IdeRootPane.myToolbar
com.intellij.openapi.actionSystem.impl.ActionToolbarImpl.myVisibleActions
java.util.ArrayList.elementData
java.lang.Object[]
com.example.ActionExample.<class>
com.example.ActionExample.<loader>
* com.intellij.ide.plugins.cl.PluginClassLoader
其它问题
可以清空下sandbox试试