java - 为什么 pluginManager.getExtensions 的结果为空?
问题描述
尝试使用 PF4J 时,我创建了必要的部分,如
- 扩展 ExtensionPoint 的接口
- 一个插件
- 带有清单的罐子
- 插件加载和激活
为什么 clickHandlers 列表是空的?
我已经使用 JUnit 测试对此进行了测试,我可以在其中调试似乎工作正常的其他部分。请参阅下面的调试日志。
我还查看了https://github.com/pf4j/pf4j/issues/21并激活了 Eclipse 注释处理,但没有任何积极影响。
1.扩展扩展点的接口
public interface ClickHandler extends ExtensionPoint {
...
}
2.一个插件
public class MBClickHandlerPlugin extends Plugin {
/**
* construct me
* @param wrapper
*/
public MBClickHandlerPlugin(PluginWrapper wrapper) {
super(wrapper);
}
@Extension
public static class MBClickHandler implements ClickHandler {
}
}
3. 带有清单的罐子
unzip -q -c target/com.bitplan.mb-0.0.1.jar META-INF/MANIFEST.MF
Manifest-Version: 1.0
Plugin-Dependencies:
Plugin-Id: com.bitplan.mb
Built-By: wf
Plugin-Provider: BITPlan GmbH
Plugin-Version: 0.0.1
Plugin-Class: com.bitplan.mb.MBClickHandlerPlugin
Created-By: Apache Maven 3.5.2
Build-Jdk: 1.8.0_152
4.插件加载和激活
/**
* activate the plugins requested on the command line
*/
public void activatePlugins() {
pluginManager = new DefaultPluginManager();
for (String plugin : plugins) {
Path pluginPath = Paths.get(plugin);
pluginManager.loadPlugin(pluginPath);
}
pluginManager.startPlugins();
List<ClickHandler> clickHandlers = pluginManager
.getExtensions(ClickHandler.class);
for (ClickHandler clickHandler : clickHandlers) {
installClickHandler(clickHandler);
}
}
调试日志
22 [main] DEBUG org.pf4j.CompoundPluginDescriptorFinder - Try to continue with the next finder
22 [main] DEBUG org.pf4j.CompoundPluginDescriptorFinder - 'org.pf4j.ManifestPluginDescriptorFinder@73d4cc9e' is applicable for plugin '/Users/wf/Documents/workspace/com.bitplan.mb/target/com.bitplan.mb-0.0.1.jar'
24 [main] DEBUG org.pf4j.AbstractPluginManager - Found descriptor PluginDescriptor [pluginId=com.bitplan.mb, pluginClass=com.bitplan.mb.MBClickHandlerPlugin, version=0.0.1, provider=BITPlan GmbH, dependencies=[], description=, requires=*, license=null]
24 [main] DEBUG org.pf4j.AbstractPluginManager - Class 'com.bitplan.mb.MBClickHandlerPlugin' for plugin '/Users/wf/Documents/workspace/com.bitplan.mb/target/com.bitplan.mb-0.0.1.jar'
24 [main] DEBUG org.pf4j.AbstractPluginManager - Loading plugin '/Users/wf/Documents/workspace/com.bitplan.mb/target/com.bitplan.mb-0.0.1.jar'
24 [main] DEBUG org.pf4j.CompoundPluginLoader - 'org.pf4j.DefaultPluginLoader@6366ebe0' is not applicable for plugin '/Users/wf/Documents/workspace/com.bitplan.mb/target/com.bitplan.mb-0.0.1.jar'
24 [main] DEBUG org.pf4j.CompoundPluginLoader - 'org.pf4j.JarPluginLoader@44f75083' is applicable for plugin '/Users/wf/Documents/workspace/com.bitplan.mb/target/com.bitplan.mb-0.0.1.jar'
25 [main] DEBUG org.pf4j.PluginClassLoader - Add 'file:/Users/wf/Documents/workspace/com.bitplan.mb/target/com.bitplan.mb-0.0.1.jar'
25 [main] DEBUG org.pf4j.AbstractPluginManager - Loaded plugin '/Users/wf/Documents/workspace/com.bitplan.mb/target/com.bitplan.mb-0.0.1.jar' with class loader 'org.pf4j.PluginClassLoader@43d7741f'
25 [main] DEBUG org.pf4j.AbstractPluginManager - Creating wrapper for plugin '/Users/wf/Documents/workspace/com.bitplan.mb/target/com.bitplan.mb-0.0.1.jar'
25 [main] DEBUG org.pf4j.AbstractPluginManager - Created wrapper 'PluginWrapper [descriptor=PluginDescriptor [pluginId=com.bitplan.mb, pluginClass=com.bitplan.mb.MBClickHandlerPlugin, version=0.0.1, provider=BITPlan GmbH, dependencies=[], description=, requires=*, license=null], pluginPath=/Users/wf/Documents/workspace/com.bitplan.mb/target/com.bitplan.mb-0.0.1.jar]' for plugin '/Users/wf/Documents/workspace/com.bitplan.mb/target/com.bitplan.mb-0.0.1.jar'
26 [main] DEBUG org.pf4j.DependencyResolver - Graph:
com.bitplan.mb -> []
26 [main] DEBUG org.pf4j.DependencyResolver - Plugins order: [com.bitplan.mb]
27 [main] INFO org.pf4j.AbstractPluginManager - Plugin 'com.bitplan.mb@0.0.1' resolved
27 [main] INFO org.pf4j.AbstractPluginManager - Start plugin 'com.bitplan.mb@0.0.1'
27 [main] DEBUG org.pf4j.DefaultPluginFactory - Create instance for plugin 'com.bitplan.mb.MBClickHandlerPlugin'
28 [main] DEBUG org.pf4j.AbstractExtensionFinder - Finding extensions of extension point 'com.bitplan.uml2mxgraph.ClickHandler'
28 [main] DEBUG org.pf4j.LegacyExtensionFinder - Reading extensions storages from classpath
28 [main] DEBUG org.pf4j.AbstractExtensionFinder - No extensions found
28 [main] DEBUG org.pf4j.LegacyExtensionFinder - Reading extensions storages from plugins
28 [main] DEBUG org.pf4j.LegacyExtensionFinder - Reading extensions storage from plugin 'com.bitplan.mb'
28 [main] DEBUG org.pf4j.LegacyExtensionFinder - Cannot find 'META-INF/extensions.idx'
28 [main] DEBUG org.pf4j.AbstractExtensionFinder - No extensions found
28 [main] DEBUG org.pf4j.AbstractExtensionFinder - Finding extensions of extension point 'com.bitplan.uml2mxgraph.ClickHandler' for plugin 'null'
28 [main] DEBUG org.pf4j.AbstractExtensionFinder - Finding extensions of extension point 'com.bitplan.uml2mxgraph.ClickHandler' for plugin 'com.bitplan.mb'
29 [main] DEBUG org.pf4j.AbstractExtensionFinder - Found 0 extensions for extension point 'com.bitplan.uml2mxgraph.ClickHandler
'
解决方案
解决方法 #1
使用定制的 PluginManager
pluginManager = new JarPluginManager(this.getClass().getClassLoader());
从将使用插件的类中确保使用相同的类加载器
JarPluginManager 源代码:
import java.nio.file.Path;
import org.pf4j.DefaultPluginManager;
import org.pf4j.JarPluginLoader;
import org.pf4j.ManifestPluginDescriptorFinder;
import org.pf4j.PluginClassLoader;
import org.pf4j.PluginDescriptor;
import org.pf4j.PluginDescriptorFinder;
import org.pf4j.PluginLoader;
import org.pf4j.PluginManager;
/**
* see https://github.com/pf4j/pf4j/issues/249 see
* https://pf4j.org/doc/class-loading.html
*
* @author wf
*
*/
public class JarPluginManager extends DefaultPluginManager {
public static class ParentClassLoaderJarPluginLoader extends JarPluginLoader {
static ClassLoader parentClassLoader;
/**
*
* @param pluginManager
*/
public ParentClassLoaderJarPluginLoader(PluginManager pluginManager) {
super(pluginManager);
}
static PluginClassLoader pluginClassLoader;
@Override
public ClassLoader loadPlugin(Path pluginPath,
PluginDescriptor pluginDescriptor) {
if (pluginClassLoader == null) {
boolean parentFirst=true;
pluginClassLoader = new PluginClassLoader(pluginManager,
pluginDescriptor, parentClassLoader,parentFirst);
}
pluginClassLoader.addFile(pluginPath.toFile());
return pluginClassLoader;
}
}
/**
* construct me with the given classloader
* @param classLoader
*/
public JarPluginManager(ClassLoader classLoader) {
ParentClassLoaderJarPluginLoader.parentClassLoader=classLoader;
//System.setProperty("pf4j.mode", RuntimeMode.DEPLOYMENT.toString());
//System.setProperty("pf4j.mode", RuntimeMode.DEVELOPMENT.toString());
}
@Override
protected PluginLoader createPluginLoader() {
// load only jar plugins
return new ParentClassLoaderJarPluginLoader(this);
}
@Override
protected PluginDescriptorFinder createPluginDescriptorFinder() {
// read plugin descriptor from jar's manifest
return new ManifestPluginDescriptorFinder();
}
}
解决方法 #2 如果未创建 extensions.idx 文件,则说明您的注释处理有问题。您可能想解决问题的根源,但也可以尝试解决它:
https://groups.google.com/forum/#!topic/pf4j/nn20axJHpfI 指出我手动创建 META-INF/extensions.idx 文件并确保静态内部类没有 args 构造函数。有了这个改变,事情就开始了。
注意在 extensions.idx 文件中正确设置类名 - 否则您将在处理程序列表中得到一个空条目
注意有一个空参数构造函数,否则你会得到一个异常
@Extension
public static class MBClickHandler implements ClickHandler {
/**
* constructor with no argument
*/
public MBClickHandler() {
}
src/main/resources/META-INF/extensions.idx
com.bitplan.mb.MBClickHandlerPlugin$MBClickHandler
要检查的代码
- extension.idx 条目的正确名称
MBClickHandler ch=new MBClickHandler();
File extFile=new File("src/main/resources/META-INF/extensions.idx");
String extidx=FileUtils.readFileToString(extFile,"UTF-8");
assertEquals(extidx,ch.getClass().getName());
- 检查扩展
List<PluginWrapper> startedPlugins = pluginManager.getStartedPlugins();
for (PluginWrapper plugin : startedPlugins) {
String pluginId = plugin.getDescriptor().getPluginId();
System.out.println(String.format("Extensions added by plugin '%s':", pluginId));
Set<String> extensionClassNames = pluginManager.getExtensionClassNames(pluginId);
for (String extension : extensionClassNames) {
System.out.println(" " + extension);
}
}
推荐阅读
- java - 如何在java中将二进制字符串转换为UTF-8文本?
- sql - 提高选择不同查询的执行时间
- java - 如何加快zxing检测?
- java - 在 Spring @Query 注释中对 Oracle / PostgreSql 使用特定的本机查询
- docx4j - 通过将 WordprocessingMLPackage 添加到主包来丢失页面方向
- oracle - 如何将 FOR LOOP 中的列值传递给使用 ORACLE 的查询?
- python - 从 Tweepy Streaming API 输出中过滤垃圾推文
- ios - AVPlayer:在 Swift 中播放“即时”转码音频文件
- ios - 由于不支持的着色器导致 IOS 中的游戏崩溃
- javascript - jsp:javascript模板文字不起作用