不推荐 Plugin extends Extension,因破坏类加载隔离导致类型校验失败;应改用接口契约(如 IExtension),由宿主类加载器统一加载接口,插件类加载器以宿主为 parent,确保类型一致性。
` 动态加载与类型校验">
Java插件化中不推荐用 Plugin extends Extension 这种继承方式实现动态加载,它会直接破坏类加载隔离的安全边界,导致类型校验失败、ClassCastException 或 NoClassDefFoundError。真正可行且稳定的做法是基于接口契约,而非继承关系。
Extension 通常是宿主定义的具体类(含字段、构造逻辑、静态初始化块等),一旦插件 JAR 中依赖并继承它,就要求该类必须在插件自己的类路径里——但插件运行时不应打包宿主类;若靠宿主类加载器提供,则因双亲委派机制,插件类加载器加载的子类与宿主加载的父类属于不同 ClassLoader 实例,JVM 认为它们是完全无关的类型,强转必然失败。
应将 Extension 抽象为纯接口(如 IExtension),不含默认方法、无静态成员、无构造器,仅声明行为契约。宿主发布独立的 api.jar,插件仅编译期依赖它,运行时不包含该 jar。
IExtension ext = (IExtension) pluginInstance;
避免 ClassCastException 的核心在于保证“接口类型”始终出自宿主类加载器,而非插件类加载器。
立即学习“Java免费学习笔记(深入)”;
Thread.currentThread().getContextClassLoader().loadClass("IExtension") 确认接口已由宿主加载new URLClassLoader(urls, hostClassLoader)
hostClassLoader.loadClass("IExtension") 获取接口 Class,再调用 asSubclass() 或安全 cast不必重写全部逻辑。可保留原有 Extension 作为内部基类,同时定义一个镜像接口 IExtension,让宿主所有扩展点面向该接口编程,并提供适配器工具类:
ExtensionAdapter 工具:接收插件实现的 IExtension,内部委托给宿主 Extension 实例(若需复用逻辑)IExtension 接口