Fork me on GitHub

To create a custom plugin manager you must choose one of with one of the options below::

  • implements PluginManager interface (create a plugin manager from scratch)
  • modifies some aspects/behaviors of built-in implementations (DefaultPluginManager)
  • extends AbstractPluginManager class

In the most common case, a plugin is a fat jar, a jar which contains classes from all the libraries, on which your project depends and, of course, the classes of current project.

AbstractPluginManager adds some glue that help you to create quickly a plugin manager. All you need to do is to implement some factory methods. PF4J uses in many places the factory method pattern to implement the dependency injection (DI) concept in a manually mode. See below the abstract methods for AbstractPluginManager:

public abstract class AbstractPluginManager implements PluginManager {

    protected abstract PluginRepository createPluginRepository();
    protected abstract PluginFactory createPluginFactory();
    protected abstract ExtensionFactory createExtensionFactory();
    protected abstract PluginDescriptorFinder createPluginDescriptorFinder();
    protected abstract ExtensionFinder createExtensionFinder();
    protected abstract PluginStatusProvider createPluginStatusProvider();
    protected abstract PluginLoader createPluginLoader();

    // other non abstract methods

}

DefaultPluginManager contributes with “default” components (DefaultExtensionFactory, DefaultPluginFactory, DefaultPluginLoader, …) to AbstractPluginManager.
Most of the times it’s enough to extends DefaultPluginManager and to supply your custom components.

Starting with version 2.0 it’s possible to coexist multiple plugins types (jar, zip, directory) in the same PluginManager. For example, DefaultPluginManager works out of the box with jar, zip and directory plugins. The idea is that DefaultPluginManager uses a compound version for:

  • PluginDescriptorFinder (CompoundPluginDescriptorFinder)
  • PluginLoader (CompoundPluginLoader)
  • PluginRepository (CompoundPluginRepository)
public class DefaultPluginManager extends AbstractPluginManager {
   
    // other methods
    
    @Override
    protected PluginDescriptorFinder createPluginDescriptorFinder() {
        return new CompoundPluginDescriptorFinder()
            .add(new PropertiesPluginDescriptorFinder())
            .add(new ManifestPluginDescriptorFinder());
    }
    
    @Override
    protected PluginRepository createPluginRepository() {
        return new CompoundPluginRepository()
            .add(new DefaultPluginRepository(getPluginsRoot(), isDevelopment()))
            .add(new JarPluginRepository(getPluginsRoot()));
    }
    
    @Override
    protected PluginLoader createPluginLoader() {
        return new CompoundPluginLoader()
            .add(new DefaultPluginLoader(this, pluginClasspath))
            .add(new JarPluginLoader(this));
    }

}

If you use only jars as plugins (no zip files, no directories), and the plugin metadata are available in MANIFEST.MF file, then you should use a custom plugin manager, something like:

PluginManager pluginManager = new DefaultPluginManager() {

    @Override
    protected PluginLoader createPluginLoader() {
        // load only jar plugins 
        return new JarPluginLoader(this);
    }

    @Override
    protected PluginDescriptorFinder createPluginDescriptorFinder() {
        // read plugin descriptor from jar's manifest 
        return new ManifestPluginDescriptorFinder();
    }

}; 

So, it’s very easy to add new strategies for plugin descriptor finder, plugin loader and plugin repository.