Classpath Zur Laufzeit bestimmte Klassen in Classloader hinzufügen?

lam_tr

Top Contributor
Hallo zusammen,

ich bastel gerade ein graphischer Editor mit Möglichkeit weitere "Plugins" / "Extensions" hinuzfügen zu können aufbasis von JavaFX.

Wie kann ich zur Laufzeit eine Jar als Plugin hinzufügen? Ich habe hier sowas gefunden hier: https://stackoverflow.com/questions/60764/how-to-load-jar-files-dynamically-at-runtime
Code:
URLClassLoader child = new URLClassLoader(
        new URL[] {myJar.toURI().toURL()},
        this.getClass().getClassLoader()
);
Class classToLoad = Class.forName("com.MyClass", true, child);
Method method = classToLoad.getDeclaredMethod("myMethod");
Object instance = classToLoad.newInstance();
Object result = method.invoke(instance);

In jede selbsterstelle Plugin Jar von mir enthält eine xml Datei, wo bestimmte Ansichten gespeichert sind. E.g. plugin1.jar -> plugin.xml
Code:
</plugin>
  <view id="mycustomview" uri="de.test.project.MyCustomView"/>
</plugin>

Wie kann ich dann die plugin.xml laden? Wenn ich 10 plugins habe, dann würde ich auch 10 plugin.xml haben. Jedes mal wenn ich ein "Add Plugin to App" mache , soll doch irgendwo die Abhängigkeit hinzugefügt werden oder? Die plugin.xml einlesen würde danach doch gehen oder getClass().getResource("plugin.xml")?

Relativ zur Anwendung habe ich ein Plugin Order, wo solche abgelegt werden sollten. Wie kann ich meine Anwendung mit solche Plugins laden, oder in die Abhängigkeit/ Classloader ergänzen?

Ich schätze das ist ein paar Sachen durcheinander geraten.

Vielleicht fangen wir mit der ersten Frage an. Wie kann ich die jar Datei zu meiner Anwendung in die Abhängigkeit hinzufügen? Als Eclipse Plugin hätte ich die manifest Datei gesagt. Aber sowas dynamisches ist schwierig zu sagen. Ich könnte auch eine XML Datei mit Jars auflisten, aber dann müsste ich auch wissen wie ich dynamisch inkludieren soll?

So was ähnliches kann ich doch aufsetzen oder plugin-dependencies.xml?
Code:
<dependencies>
   <plugin>de.test.plugin1.jar</plugin>
   <plugin>de.test.plugin2.jar</plugin> 
   <plugin>de.test.plugin3.jar</plugin>
   <plugin>de.test.plugin4.jar</plugin>
</dependencies>
Grüße
lam
 
K

kneitzel

Gast
Dein genaues Vorhaben / Problem ist mir noch nicht ganz klar:

Wenn die Applikation dynamisch Erweiterungen laden können soll, dann stellt sich erst einmal die Frage nach dem Classloader: Für welche Funktionalität benötigst Du ein dynamisches Laden über einen selbst erstellten Classloader? Reicht es nicht schon aus, wenn man einfach die Applikation so startet, dass alle jar Dateien eines Verzeichnisses im ClassPath enthalten sind? => Beim Start wären dann alle Klassen verfügbar.
Das wäre also sowas wie ./plugins/* innerhalb des classpaths.

Oder benötigst Du irgendwelche erweiterten Funktionen a.la. hinzufügen / entfernen / aktualisieren von Abhängigkeiten, so dass da kein Neustart der Applikation in Frage kommt?

Das wäre dann ein erster, einfacher Start, um eben auf Klassen zur Laufzeit zugreifen zu können.

Dann bleibt die Frage nach der Konfiguration: Da kannst Du natürlich alles nutzen, was es gibt: Angefangen von einfachen properties-Dateien über entsprechende XML Dateien. Diese liest du dann mit den entsprechenden Mitteln ein und wertest die Daten dann aus. So eine XML Datei könnte einfach etwas serialisiertes sein.
Und was da benötigt wird, sind in erster Linie z.B. ein Klassenname, von dem dann eine Instanz erzeugt wird und die dann ein gewisses Interface implementiert. (Das wäre so mein Ansatz).

Aber wenn Du etwas ausführlicher schreibst, was Du genau möchtest, dann kann man ggf. konkretere Hilfe geben.
 

lam_tr

Top Contributor
Dein genaues Vorhaben / Problem ist mir noch nicht ganz klar:

Wenn die Applikation dynamisch Erweiterungen laden können soll, dann stellt sich erst einmal die Frage nach dem Classloader: Für welche Funktionalität benötigst Du ein dynamisches Laden über einen selbst erstellten Classloader? Reicht es nicht schon aus, wenn man einfach die Applikation so startet, dass alle jar Dateien eines Verzeichnisses im ClassPath enthalten sind? => Beim Start wären dann alle Klassen verfügbar.
Das wäre also sowas wie ./plugins/* innerhalb des classpaths.

Oder benötigst Du irgendwelche erweiterten Funktionen a.la. hinzufügen / entfernen / aktualisieren von Abhängigkeiten, so dass da kein Neustart der Applikation in Frage kommt?

Das wäre dann ein erster, einfacher Start, um eben auf Klassen zur Laufzeit zugreifen zu können.

Dann bleibt die Frage nach der Konfiguration: Da kannst Du natürlich alles nutzen, was es gibt: Angefangen von einfachen properties-Dateien über entsprechende XML Dateien. Diese liest du dann mit den entsprechenden Mitteln ein und wertest die Daten dann aus. So eine XML Datei könnte einfach etwas serialisiertes sein.
Und was da benötigt wird, sind in erster Linie z.B. ein Klassenname, von dem dann eine Instanz erzeugt wird und die dann ein gewisses Interface implementiert. (Das wäre so mein Ansatz).

Aber wenn Du etwas ausführlicher schreibst, was Du genau möchtest, dann kann man ggf. konkretere Hilfe geben.

Also es geht mir hier darum einfach ein generischen Editor zu entwickeln der Plugins für Shapes, für Diagramme, etc. als Erweiterung anzubieten. Nicht jeder will von vorne herein alles haben. Deswegen will ich nur dieser Editor Workbench als Gerüst als Start verpacken und die anderen Plugins als zusätzliche Pakete, die man im Laufe der Zeit in das Gerüst als Benutzer nachinstallieren kann.

Auch dem Benutzer ist überlassen, eigene Plugins zu schreiben. Somit kann er auch selbst sein Plugin in das Workbench reinladen.

Wenn die Applikation dynamisch Erweiterungen laden können soll, dann stellt sich erst einmal die Frage nach dem Classloader: Für welche Funktionalität benötigst Du ein dynamisches Laden über einen selbst erstellten Classloader? Reicht es nicht schon aus, wenn man einfach die Applikation so startet, dass alle jar Dateien eines Verzeichnisses im ClassPath enthalten sind? => Beim Start wären dann alle Klassen verfügbar.
Das wäre also sowas wie ./plugins/* innerhalb des classpaths.

Zu deiner ersten Frage: Ich weiß zu dem Start der Anwendung nicht wieviele plugin jars noch nachkommen. Aber das heißt auch, jedes mal wenn ich eine neue Plugin implementiere, dann muss ich auch das Projekt in meine Applikation inkludieren. Was ist wenn ich nur plugins entwickeln kann aber keinen Zugriff auf die Applikation?

Oder benötigst Du irgendwelche erweiterten Funktionen a.la. hinzufügen / entfernen / aktualisieren von Abhängigkeiten, so dass da kein Neustart der Applikation in Frage kommt?
Wenn ich ein plugin hinzufüge und zur Laufzeit wird es gezogen ohne Neuzustarten wäre optimal, aber ich sag mal ich bin auch bereit neuzustarten wenn die Abhängigkeiten gezogen werden.

Ich versuche schon das einlesen der Jar zu realisieren, komme leider nicht an die plugin.xml ran. Wie kann ich von InputStream zur File("test.resource") kommen? Das wäre jetzt ein Beispiel dieser Seite https://stackoverflow.com/questions/5957589/load-resource-from-jar-file-at-runtime
Code:
JarFile jarFile = new JarFile(new File("/out/resource.jar"))
JarEntry jarEntry = jarFile.getJarEntry("test.resource")
InputStream inputStream = jarFile.getInputStream(jarEntry)

An sich will ich sowas wie Eclipse nachbauen aber ohne OSGI.
 
K

kneitzel

Gast
Also nur als Beispiel: Schau Dir JDBC an!

Da hast Du eine Library, die gewisse Dinge implementiert. Du kannst beliebig viele JDBC Treiber im Klassenpfad haben. Generell muss die Applikation noch nicht einmal wissen, was für eine JDBC Library verwendet wird - der connection string ist dann halt unterschiedlich....

Und mal angenommen, du wolltest einen JDBC Treiber selbst entwickeln: Du brauchst natürlich keinen Zugriff auf die späteren Applikationen, die diesen verwenden wollen. Aber natürlich brauchst Du Zugriff auf gewisse Dinge, die Du implementieren sollst.

So macht es durchaus Sinn, dass Du Dinge, die als Grundlage dienen und auch von einem Plugin benötigt werden (also Interfaces, Basisklassen, ...) in einer separaten Library bereit stellst. Dann hast eine klarere Abhängigkeiten...

Und die jar so als Archiv einlesen? Wenn, dann würde ich es wirklich über den ClassLoader machen - also Dein erster Ansatz. Denn Du willst ja auch Klassen nutzen und so ... Aber da wäre meine Frage immer: Wozu? Eine JDBC Library willst Du so ja auch nicht einbinden ... Die wird einfach in den Pfad kopiert und dann steht sie zur Verfügung. Damals noch das Erzeugen einer Klasse über Name, aber das entfällt ja seid JDBC 4.0 auch auf Grund der ServiceLoader Funktionalität (https://docs.oracle.com/javase/7/docs/api/java/util/ServiceLoader.html).

Wäre das nicht so viel schöner? Die AddOns kommen einfach in ein Verzeichnis, das beim Start im ClassPath ist. Durch einen ServiceLoader Eintrag können die sich selbst registrieren. Du kannst dann in der Applikation ja dann eine normale Verwaltung haben so von wegen aktiviertes AddOn oder Deaktiviertes AddOn.

Etwas in der Art wäre halt mein erster Ansatz bezüglich eines AddOns. Und da irgendwelche Daten aus der JAR Datei ziehen? Das würde ich dem Entwickler des AddOns überlassen. Wenn irgendwelche Informationen z.B. über das AddOn benötigt würden, dann wäre das im Interface z.B. vom AddOn enthalten. Also wenn Du für jedes AddOn wissen willst: Kann das AddOn den Rechner zerstören, dann gibt es halt ein Interface AddOn und das hat die Methode boolean canDestroyComputer(); Bei der Registrierung muss das AddOn halt eine Instanz von AddOn hinterlegen und die würdest Du dann nutzen ...

Waren diese Überlegungen halbwegs verständlich und vielleicht etwas hilfreich?
 

lam_tr

Top Contributor
Klasse erklärt danke, ich glaube das mit dem ServiceLoader ist was ich benötige.

Ich habe zwar jetzt alles über ClassLoader gemacht, aber ServiceLoader sollte etwas sauberer sein oder?

Code:
public class PluginService implements IPluginService {

    private File folder = new File("plugins");

    public PluginService() {
        if (!folder.exists()) {
            folder.mkdir();
        }
    }

    @Override
    public WorkbenchModul loadPlugin(File jar) {
        try {
            URL url = jar.toURI().toURL();
            URL[] urls = new URL[] { url };
            URLClassLoader classLoader = new URLClassLoader(urls, ClassLoader.getSystemClassLoader());
            Thread.currentThread().setContextClassLoader(classLoader);

            JarFile jarFile = new JarFile(jar);
            JarEntry jarEntry = jarFile.getJarEntry("resources/base.modul");
            InputStream inputStream = jarFile.getInputStream(jarEntry);

            org.eclipse.emf.ecore.resource.Resource res = null;
            res = new XMIResourceImpl();

            HashMap options = new HashMap();
            options.put(XMIResource.OPTION_DECLARE_XML, Boolean.TRUE);
            try {
                res.load(inputStream, options);

                WorkbenchModul model = (WorkbenchModul) res.getContents().get(0);
                return model;
            } catch (IOException e) {
                e.printStackTrace();
            }

            jarFile.close();
        } catch (Exception ex) {
            throw new RuntimeException(
                    "Cannot load library from jar file '" + jar.getAbsolutePath() + "'. Reason: " + ex.getMessage());
        }
        return null;
    }

    @Override
    public List<String> getPluginNames() {
        return Arrays.asList(folder.list());
    }

    @Override
    public List<File> getPlugins() {
        return Arrays.asList(folder.listFiles());
    }

    @Override
    public void addPluginToClassPath(File jar) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, MalformedURLException {
        // Get the ClassLoader class
        ClassLoader cl = ClassLoader.getSystemClassLoader();
        Class<?> clazz = cl.getClass();
      
        // Get the protected addURL method from the parent URLClassLoader class
        Method method = clazz.getSuperclass().getDeclaredMethod("addURL", new Class[] {URL.class});
      
        // Run projected addURL method to add JAR to classpath
        method.setAccessible(true);
        method.invoke(cl, new Object[] {jar.toURI().toURL()});
    }

    @Override
    public List<WorkbenchModul> loadPlugins() throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, MalformedURLException {
        List<WorkbenchModul> modules = new ArrayList<>();
        for (File plugin : getPlugins()) {
            addPluginToClassPath(plugin);
            modules.add(loadPlugin(plugin));
        }
        return modules;
    }

}
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
S Build-Zeitpunt (Datum und Uhrzeit) irgendwie während der Laufzeit zugänglich machen..? Allgemeine Java-Themen 4
M Laufzeit des Prim Algorithmus Allgemeine Java-Themen 3
M Laufzeit LinkedList Allgemeine Java-Themen 9
M verbesserte Laufzeit bei LinkedList Allgemeine Java-Themen 7
K Verbesserung der Laufzeit beim Sortieren von Einwohnern nach ihrem Geburtsjahr Allgemeine Java-Themen 0
H was ist den dieses zur Kompilierzeit und zur Laufzeit in Java? Allgemeine Java-Themen 3
L Compiler-Fehler Google Guice Module zur Laufzeit zusammenstellen und binden Allgemeine Java-Themen 4
J Jasper Reports - Subreport zur Laufzeit ändern Allgemeine Java-Themen 6
O jar und EXE Dateien, Pfade zur Laufzeit Allgemeine Java-Themen 1
T Externe Java Klasen zur Laufzeit einbinden Allgemeine Java-Themen 10
X Collections Gibt es eine Klasse welche die Vorteile von List und HashMap vereint, aber konstante Laufzeit (O(1)) hat in Java? Allgemeine Java-Themen 4
D Boolean von ein anderem Java Programm während der Laufzeit ändern Allgemeine Java-Themen 23
N Generic Type einer Generischen Klasse während der Laufzeit bekommen Allgemeine Java-Themen 2
J .java-Dateitext Compile zur Laufzeit ohne File Allgemeine Java-Themen 15
kodela Daten während Laufzeit zugriffsbereit Allgemeine Java-Themen 15
Neumi5694 Interpreter-Fehler final Eigenschaft während Laufzeit geändert Allgemeine Java-Themen 2
A Java Klasse auf Tomcat während der Laufzeit austauschen Allgemeine Java-Themen 1
M Sinn von Kompilierung zur Laufzeit Allgemeine Java-Themen 3
T Java Class Intrumentation mit Annotations in Laufzeit Allgemeine Java-Themen 1
S Byte Array welches in Laufzeit aufgelöst wird // Objekt Array Allgemeine Java-Themen 3
T Dateien zur Laufzeit in Java-Programm packen? Allgemeine Java-Themen 3
S Laufzeit Primzahlgenerator Allgemeine Java-Themen 18
S Zur Laufzeit Klasse mit einer anzahl von X Objekten erstellen Allgemeine Java-Themen 5
F Classpath Programmteile zur Laufzeit nachladen Allgemeine Java-Themen 6
D Variablen zur Laufzeit global speichern (Registry Pattern?) Allgemeine Java-Themen 6
H ResourceBundle während Laufzeit bearbeiten Allgemeine Java-Themen 3
J Input/Output Jar-Datei zur Laufzeit erweitern Allgemeine Java-Themen 13
P Generic zur Laufzeit Allgemeine Java-Themen 4
A ar während der Laufzeit überschreiben Allgemeine Java-Themen 20
X MergeSort Laufzeit Problem Allgemeine Java-Themen 4
J Resourcen waehrend der Laufzeit aendern? Allgemeine Java-Themen 9
P Wie bei log4j den Dateipfad der Logdatei zur Laufzeit ändern? Allgemeine Java-Themen 3
X Update einer Jar während der Laufzeit Allgemeine Java-Themen 8
T Klassen Fabrik (Factory) zur Laufzeit erweitern Allgemeine Java-Themen 5
S UML zur Laufzeit ändern Allgemeine Java-Themen 10
E Wert von enum zur Laufzeit festlegen. Allgemeine Java-Themen 5
L Methode in Thread mit langer Laufzeit unterbrechen (ANT executeTarget) Allgemeine Java-Themen 4
O Problem bei Darstellung der Laufzeit eines Programms Allgemeine Java-Themen 3
hdi Ressourcen dynamisch zur Laufzeit laden Allgemeine Java-Themen 15
A Wie zur Laufzeit auf Objekte zugreifen Allgemeine Java-Themen 7
N variable Anzahl von Objektinstanzen zur Laufzeit erstellen Allgemeine Java-Themen 4
P Java Konsole zur Laufzeit einblenden Allgemeine Java-Themen 4
P Klassenwahl zur Laufzeit Allgemeine Java-Themen 5
R Objekt zur Laufzeit zerstören? Allgemeine Java-Themen 12
E formartierte Ausgabe zur Laufzeit Allgemeine Java-Themen 2
Sonecc Zugriff auf Class File einer anderen Jar während der Laufzeit Allgemeine Java-Themen 2
F Wie zur Laufzeit ganz neue Objekte erzeugen? Allgemeine Java-Themen 5
T Class-files zur Laufzeit zu Reflection-Zwecken laden Allgemeine Java-Themen 18
DamienX Debug Modus zur Laufzeit erkennen Allgemeine Java-Themen 3
Stillmatic Debuggen/ Laufzeit von Methoden Allgemeine Java-Themen 2
Dragonfire Generic Typ zur Laufzeit Allgemeine Java-Themen 9
M Klasse zur Laufzeit ersetzen Allgemeine Java-Themen 10
S Wie gross ist die Laufzeit für diese Schleife?? Allgemeine Java-Themen 8
G File zur Laufzeit erzeugen Allgemeine Java-Themen 4
G Jar File zur Laufzeit ändern. Allgemeine Java-Themen 4
T Java - Compilieren während Laufzeit Allgemeine Java-Themen 3
Y JARs austauschen zur Laufzeit Allgemeine Java-Themen 11
G Datenbank zur laufzeit wechseln Allgemeine Java-Themen 11
C Innere Klassen zur Laufzeit Instanzieren Allgemeine Java-Themen 4
T Zur Laufzeit erben? Allgemeine Java-Themen 22
L HashMap / Objekte auf Festplatte zur Laufzeit auf HD swappen Allgemeine Java-Themen 7
L Zur Laufzeit eine Klasse laden, die auf jar-File zugreift Allgemeine Java-Themen 15
V Java-Programm weiss zur Laufzeit wie es gestartet wurde? Allgemeine Java-Themen 6
N Endlosschleifen automatisiert erkennen (Code oder Laufzeit)? Allgemeine Java-Themen 6
G Eindeutiges Identifizieren einer JTable/Component z.laufzeit Allgemeine Java-Themen 2
G Datei durchsuchen, lange Laufzeit! Allgemeine Java-Themen 2
A log4j 1.3 und ändern der log Konfiguration zur Laufzeit Allgemeine Java-Themen 4
Apo Zur Laufzeit Klassen mit Packages laden? Allgemeine Java-Themen 2
G genauen Typ einer generischen Klasse zur Laufzeit ermitteln Allgemeine Java-Themen 2
F Typ eines Objekts zur Laufzeit bestimmen? Allgemeine Java-Themen 8
T xverify-parameter : Workaround zur Laufzeit? Allgemeine Java-Themen 8
M Bibliotheksname zur Laufzeit ermitteln (Classloader) Allgemeine Java-Themen 7
G Klasse wird zur Laufzeit nicht gefunden? Allgemeine Java-Themen 3
@ zur Laufzeit Interface aus jar implementieren? Allgemeine Java-Themen 5
MQue Laufzeit Allgemeine Java-Themen 4
D Lautstärke einzelner AudioClips zur Laufzeit verändern Allgemeine Java-Themen 4
C Mathefunktion zur Laufzeit einlesen und dann verarbeiten Allgemeine Java-Themen 13
G Klassen zur Laufzeit einbinden Allgemeine Java-Themen 3
J Bibliotheken erst zur Laufzeit laden Allgemeine Java-Themen 5
R Drag und Drop - Fehler während Laufzeit Allgemeine Java-Themen 14
byte Generic Type einer List zur Laufzeit rausfinden? Allgemeine Java-Themen 4
A Class File zur Laufzeit laden ohne den Binary Name zu kennen Allgemeine Java-Themen 11
M Überprüfen einer zur Laufzeit geladenen Klasse Allgemeine Java-Themen 3
H Klassen aus einem Ordner zur Laufzeit laden. Allgemeine Java-Themen 6
S Laufzeit und Compilefehler Allgemeine Java-Themen 6
S JPanel zur Laufzeit verbergen bzw. wieder anzeigen lassen Allgemeine Java-Themen 4
F Objektname zur Laufzeit festlegen? Allgemeine Java-Themen 12
I Sprache zur Laufzeit des Programms ändern Allgemeine Java-Themen 3
G Laufzeit eines aus Java gestarteten Programms beobachten Allgemeine Java-Themen 3
S Log4J: Logdatei zur Laufzeit ermitteln. Allgemeine Java-Themen 2
I Zur Laufzeit ermitteln, ob Klasse in JAR-Datei Allgemeine Java-Themen 2
R iText.jar wird zur Laufzeit nicht gefunden Allgemeine Java-Themen 4
J ResourceBundle / properties-datei während der Laufzeit verän Allgemeine Java-Themen 6
H Methode einer zur Laufzeit generierten Instanz aufrufen Allgemeine Java-Themen 2
M Formel in einem String während Laufzeit berechnen. Allgemeine Java-Themen 4
JavaJakob22 Bestimmte HashMap importieren Allgemeine Java-Themen 4
C Aus MEHREREN Excel Tabellen bestimmte Zelle addieren Allgemeine Java-Themen 1
J Eine bestimmte Zahl im Integer ändern Allgemeine Java-Themen 9
J Bestimmte Zeile aus Textdatei auslesen Allgemeine Java-Themen 18
C Eclipse einstellen, dass eine bestimmte JDK benutzt werden soll Allgemeine Java-Themen 3

Ähnliche Java Themen

Neue Themen


Oben