Suche…


Bemerkungen

Wenn Sie eine IDE und / oder ein Build-System verwenden, ist das Einrichten dieser Art von Projekt viel einfacher. Sie erstellen ein Hauptanwendungsmodul, dann ein API-Modul, dann ein Plugin-Modul und machen es vom API-Modul oder von beiden abhängig. Als Nächstes konfigurieren Sie, wo die Projektartefakte platziert werden sollen. In unserem Fall können die kompilierten Plug-In-Jars direkt in das Plug-In-Verzeichnis gesendet werden, sodass keine manuellen Bewegungen erforderlich sind.

URLClassLoader verwenden

Es gibt verschiedene Möglichkeiten, ein Plug-In-System für eine Java-Anwendung zu implementieren. Eine der einfachsten ist die Verwendung von URLClassLoader . Das folgende Beispiel enthält etwas JavaFX-Code.

Angenommen, wir haben ein Modul einer Hauptanwendung. Dieses Modul soll Plugins in Form von Jars aus dem Plugins-Ordner laden. Anfangscode:

package main;

public class MainApplication extends Application
{
    @Override
    public void start(Stage primaryStage) throws Exception
    {
        File pluginDirectory=new File("plugins"); //arbitrary directory
        if(!pluginDirectory.exists())pluginDirectory.mkdir();
        VBox loadedPlugins=new VBox(6); //a container to show the visual info later
        Rectangle2D screenbounds=Screen.getPrimary().getVisualBounds();
        Scene scene=new Scene(loadedPlugins,screenbounds.getWidth()/2,screenbounds.getHeight()/2);
        primaryStage.setScene(scene);
        primaryStage.show();
    }
    public static void main(String[] a)
    {
            launch(a);
    }
}

Dann erstellen wir eine Schnittstelle, die ein Plugin darstellt.

package main;

public interface Plugin
{
    default void initialize()
    {
        System.out.println("Initialized "+this.getClass().getName());
    }
    default String name(){return getClass().getSimpleName();}
}

Wir möchten Klassen laden, die diese Schnittstelle implementieren. Daher müssen wir zunächst Dateien filtern, die die Erweiterung '.jar' haben:

File[] files=pluginDirectory.listFiles((dir, name) -> name.endsWith(".jar"));

Wenn Dateien vorhanden sind, müssen Sammlungen von URLs und Klassennamen erstellt werden:

    if(files!=null && files.length>0)
    {
        ArrayList<String> classes=new ArrayList<>();
        ArrayList<URL> urls=new ArrayList<>(files.length);
        for(File file:files)
        {
            JarFile jar=new JarFile(file);
            jar.stream().forEach(jarEntry -> {
                if(jarEntry.getName().endsWith(".class"))
                {
                    classes.add(jarEntry.getName());
                }
            });
            URL url=file.toURI().toURL();
            urls.add(url);
        }
        
    }

Fügen wir der MainApplication ein statisches HashSet hinzu, das geladene Plugins enthält:

static HashSet<Plugin> plugins=new HashSet<>();

Als Nächstes instantiieren wir einen URLClassLoader und iterieren über Klassennamen und instanziieren Klassen, die die Plugin- Schnittstelle implementieren:

URLClassLoader urlClassLoader=new URLClassLoader(urls.toArray(new URL[urls.size()]));
classes.forEach(className->{
    try
    {
        Class cls=urlClassLoader.loadClass(className.replaceAll("/",".").replace(".class","")); //transforming to binary name
        Class[] interfaces=cls.getInterfaces();
        for(Class intface:interfaces)
        {
            if(intface.equals(Plugin.class)) //checking presence of Plugin interface
            {
                Plugin plugin=(Plugin) cls.newInstance(); //instantiating the Plugin
                plugins.add(plugin);
                break;
            }
        }
    }
    catch (Exception e){e.printStackTrace();}
});

Dann können wir zum Beispiel Plugins-Methoden aufrufen, um sie zu initialisieren:

if(!plugins.isEmpty())loadedPlugins.getChildren().add(new Label("Loaded plugins:"));
    plugins.forEach(plugin -> {
        plugin.initialize();
        loadedPlugins.getChildren().add(new Label(plugin.name()));
});

Der endgültige Code von MainApplication :

package main;
public class MainApplication extends Application
{
    static HashSet<Plugin> plugins=new HashSet<>();
    @Override
    public void start(Stage primaryStage) throws Exception
    {
        File pluginDirectory=new File("plugins");
        if(!pluginDirectory.exists())pluginDirectory.mkdir();
        File[] files=pluginDirectory.listFiles((dir, name) -> name.endsWith(".jar"));
        VBox loadedPlugins=new VBox(6);
        loadedPlugins.setAlignment(Pos.CENTER);
        if(files!=null && files.length>0)
        {
            ArrayList<String> classes=new ArrayList<>();
            ArrayList<URL> urls=new ArrayList<>(files.length);
            for(File file:files)
            {
                JarFile jar=new JarFile(file);
                jar.stream().forEach(jarEntry -> {
                    if(jarEntry.getName().endsWith(".class"))
                    {
                        classes.add(jarEntry.getName());
                    }
                });
                URL url=file.toURI().toURL();
                urls.add(url);
            }
            URLClassLoader urlClassLoader=new URLClassLoader(urls.toArray(new URL[urls.size()]));
            classes.forEach(className->{
                try
                {
                    Class cls=urlClassLoader.loadClass(className.replaceAll("/",".").replace(".class",""));
                    Class[] interfaces=cls.getInterfaces();
                    for(Class intface:interfaces)
                    {
                        if(intface.equals(Plugin.class))
                        {
                            Plugin plugin=(Plugin) cls.newInstance();
                            plugins.add(plugin);
                            break;
                        }
                    }
                }
                catch (Exception e){e.printStackTrace();}
            });
            if(!plugins.isEmpty())loadedPlugins.getChildren().add(new Label("Loaded plugins:"));
            plugins.forEach(plugin -> {
                plugin.initialize();
                loadedPlugins.getChildren().add(new Label(plugin.name()));
            });
        }
        Rectangle2D screenbounds=Screen.getPrimary().getVisualBounds();
        Scene scene=new Scene(loadedPlugins,screenbounds.getWidth()/2,screenbounds.getHeight()/2);
        primaryStage.setScene(scene);
        primaryStage.show();
    }
    public static void main(String[] a)
    {
            launch(a);
    }
}

Lassen Sie uns zwei Plugins erstellen. Natürlich sollte sich die Quelle des Plugins in einem separaten Modul befinden.

package plugins;

import main.Plugin;

public class FirstPlugin implements Plugin
{
    //this plugin has default behaviour
}

Zweites Plugin:

package plugins;

import main.Plugin;

public class AnotherPlugin implements Plugin
{
    @Override
    public void initialize() //overrided to show user's home directory
    {
        System.out.println("User home directory: "+System.getProperty("user.home"));
    }
}

Diese Plugins müssen in Standard-Jars gepackt werden - dieser Vorgang hängt von Ihrer IDE oder anderen Tools ab.

Wenn Jars direkt in 'Plugins' eingefügt werden, erkennt MainApplication diese und instanziiert entsprechende Klassen.



Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow