pf4j 支持直接在应用中进行插件的开发以及运行(不需要复杂的处理)
与serviceloader 比较类似,我么只需要添加一个注解就可以了(@Extension)
参考运行
public static void main(String[] args) {
PluginManager pluginManager = new DefaultPluginManager();
// pluginManager.loadPlugins();
// pluginManager.startPlugins();
List<Greeting> greetings = pluginManager.getExtensions(Greeting.class);
for (Greeting greeting : greetings) {
System.out.println(">>> " + greeting.getGreeting());
}
}
实现原理
主要是 DefaultPluginManager 的默认实现,包含的一个createExtensionFinder方法
@Override
protected ExtensionFinder createExtensionFinder() {
DefaultExtensionFinder extensionFinder = new DefaultExtensionFinder(this);
addPluginStateListener(extensionFinder);
return extensionFinder;
}
默认实现的处理,添加了一个自己的LegacyExtensionFinder
public DefaultExtensionFinder(PluginManager pluginManager) {
this.pluginManager = pluginManager;
// 添加默认的LegacyExtensionFinder
add(new LegacyExtensionFinder(pluginManager));
// add(new ServiceProviderExtensionFinder(pluginManager));
}
LegacyExtensionFinder class 查找处理,使用了基类的 AbstractExtensionFinder.java
private Map<String, Set<String>> readStorages() {
Map<String, Set<String>> result = new LinkedHashMap<>();
result.putAll(readClasspathStorages());
result.putAll(readPluginsStorages());
return result;
}
LegacyExtensionFinder readClasspathStorages 实现处理,先直接查询的classpath,就能确保使用应用的扩展接口
public Map<String, Set<String>> readClasspathStorages() {
log.debug("Reading extensions storages from classpath");
Map<String, Set<String>> result = new LinkedHashMap<>();
Set<String> bucket = new HashSet<>();
try {
Enumeration<URL> urls = getClass().getClassLoader().getResources(EXTENSIONS_RESOURCE);
if (urls.hasMoreElements()) {
collectExtensions(urls, bucket);
} else {
log.debug("Cannot find '{}'", EXTENSIONS_RESOURCE);
}
debugExtensions(bucket);
result.put(null, bucket);
} catch (IOException e) {
log.error(e.getMessage(), e);
}
return result;
}
参考资料
https://pf4j.org/doc/system-extension.html