Merkwürdiges Problem mit URLClassLoader und Interfaces

S

SE

Hi Fans,
ich hätte da auch mal wieder n Thread bei dem ihr euch die Köpfe zerbrechen könnt.

Worum geht es :
es geht grob gesagt um mein Plug-In - System und einen merkwürdigen Fehler mit einem Interface

Wie genau liegen die Klassen vor ?
Alle Klassen sind in JAR-Files gepackt. Die Struktur versuche ich mal schemahaft darzubringen.
Code:
root-dir
+--> Launcher.jar
  +-> projekt/pfad/Launcher.class
  +-> projekt/lib/pluginSystem/Plugin.class
  +-> projekt/lib/pluginSystem/PluginLoader.class
+--> Loader.jar
  +-> projekt/pfad/Loader.class
+--> SomePlugin.jar
  +-> projekt/pfad/plugin/Some.class

Wo liegt das Problem ?
Zur Zeit habe ich wie ihr seht meine Plugin-Interfaces im Launcher.jar welches von der VM dierekt gestartet wird. In der Klasse Launcher wird neben Updates dann auch irgendwann die Klass Loader aufgerufen. Der Loader läd die Plugins, registriert und startet diese.
Jetzt das Problem : so bald ich die Interface-Klassen des pluginSystems aus dem Launcher.jar in das Loader.jar packe bekomme ich ClassDefNotFoundException's.
Ich habe auch versucht in der Klasse Loader über
Java:
this.getClass().getClassLoader().loadClass(String)
versucht die Klassen manuell nachzuladen ... aber das funktioniert bei Interfaces scheinbar nicht.
Die Loader.jar wird über einen URLClassLoader vom Launcher.jar aus geladen. Ich dachte das durch den URLClassLoader auch die Interface-Klassen des pluginSystems geladen werden ... aber dem ist scheinbar nicht so. Das komisch ist das die Klasse Plugin beim laden eines Plugins angemerkt wird ... die Klasse PluginLoader von der die Klasse Loader abgeleitet ist jedoch nicht. Und das auch außerhalb des CLASSPATH *habe diesen zum Test entfernt und das ganze in einem anderen Verzeichnis ausgeführt ... Ergebnis war das selbe.

Nun meine Frage an euch :
Wie muss ich meinen Source umschreiben damit die Interface-Klassen aus dem via URLClassLoader geladenem Loader.jar geladen werden und somit nicht im Launcher.jar liegen müssen ?

Source stelle ich bei bedarf auch rein ... aber ich hoffe das mir das jemand anhand des Schemas erklären kann.
 
Zuletzt bearbeitet von einem Moderator:
Hallo,

leider blicke ich bei deinem Post nicht so recht durch...
Wie soll dein "Plug-in" System denn genau funktionieren?

Gruß Tom
 
Also,
der Launcher ist das Jar welches als Argument and Java übergeben wird.
Nach dem der Launcher alle wichtigen Updates durchgeführt hat *Launcher.jar selbst , Updater.jar und über diese alle anderen JAR-Files* läd der Launcher das Loader.jar über einen URLClassLoader. In diesem Loader.jar ist die Klasse Loader welche für das Laden der Plugins verantwortlich ist. Damit der Loader nun aber die unterschiedlichen Plugins laden kann werden diese natürlich alle auf das Interface Plugin gecastet. So lange die Plugin-Interface-Klassen *Plugin und PluginLoader* im Launcher.jar sind funktioniert das auch alles. Sobald ich jetzt aber die Interface klassen ins Loader.jar verschiebe steigt Java mit einer ClassDefNotFoundException aus da scheinbar die Interface-Klasse Plugin nicht gefunden werden kann.

Meine frage bezieht sich jetzt darauf warum das so ist obwohl das Interface Plugin über den URLClassLoader verfügbar sein müsste.

Wenn du immer noch nicht durchblickst bastel ich schnell mal ein compilebares Beispiel und lade beide Varianten *einmal Interfaces im Launcher und einmal im Loader* hoch das ihr seht was ich meine.
 
Hallo,

1) deine Experimente in allen ehren, aber ich möchte hier gerne erwähnen das für exakt solche Situationen mit dem java.util.ServiceLoader<S> API bereits im Java Standard eine sehr einfache aber dennoch mächtige Infrastruktur zur Realisierung von Plug-in Mechanismen zur Verfügung steht.
http://www.tutorials.de/java/357126-wieder-mal-java-und-plug-ins.html#post1850187
http://www.tutorials.de/java/358931-services-dynamisch-laden.html#post1859684
Aber ich weis ja du willst erstmal alles selber machen :) Deshalb halte ich mich mit meinen Ratschlägen etwas zurück.

2) hier ein kleines Beispiel (so wie ichs verstanden habe... oder lädst du deinen Loader auch per Reflection?) :
Code:
C:\temp\java\training>dir /s
 Datenträger in Laufwerk C: ist SYSTEM
 Volumeseriennummer: E012-F399

 Verzeichnis von C:\temp\java\training

28.06.2011  00:30    <DIR>          .
28.06.2011  00:30    <DIR>          ..
28.06.2011  00:29               702 app.jar
28.06.2011  00:29             3.008 loader.jar
28.06.2011  00:18    <DIR>          plugins
               2 Datei(en),          3.710 Bytes

 Verzeichnis von C:\temp\java\training\plugins

28.06.2011  00:18    <DIR>          .
28.06.2011  00:18    <DIR>          ..
28.06.2011  00:20               819 CorePlugin.jar
               1 Datei(en),            819 Bytes

In app.jar:

App:
Java:
package de.tutorials.app;

import de.tutorials.app.plugin.Loader;

public class App {
	public static void main(String[] args) {
		new App().start();
	}

	private void start() {
		Loader loader = new Loader();
		loader.load();
	}
}

In loader.jar:

Loader:
Java:
package de.tutorials.app.plugin;

import java.io.File;
import java.io.FilenameFilter;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;

public class Loader {
	public void load(){
		List<URL> plugins = new ArrayList<URL>();
		for(File plugin : new File("plugins").listFiles(newJarFileFilter())){
			try {
				plugins.add(plugin.toURI().toURL());
			} catch (MalformedURLException e) {
				e.printStackTrace();
			}
		}
		start(plugins);
	}

	private void start(List<URL> plugins) {
		URLClassLoader loader = new URLClassLoader(plugins.toArray(new URL[plugins.size()]));
		
		for(URL u : plugins){
			String pluginClassName = getPluginClassName(u);
			System.out.println("starting: " + pluginClassName);
			try {
				Plugin plugin = (Plugin)loader.loadClass(pluginClassName).newInstance();
				plugin.start();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	String getPluginClassName(URL u) {
		String pluginSimpleClassName = u.toString().substring(u.toString().lastIndexOf('/')+1).replace(".jar", "");
		String pluginClassName = getClass().getPackage().getName()+"."+pluginSimpleClassName;
		return pluginClassName;
	}

	FilenameFilter newJarFileFilter() {
		return new FilenameFilter() {
			@Override
			public boolean accept(File dir, String name) {
				return name.endsWith(".jar");
			}
		};
	}
}

Plugin:
Java:
package de.tutorials.app.plugin;

public interface Plugin {
	void start();
}

In CorePlugin.jar unser CorePlugin:
Java:
package de.tutorials.app.plugin;

public class CorePlugin implements Plugin{
  public void start() {
    System.out.println(super.getClass() + " start ");
  }
}

Ausgabe:
Code:
C:\temp\java\training>java -cp app.jar;loader.jar de.tutorials.app.App
starting: de.tutorials.app.plugin.CorePlugin
class de.tutorials.app.plugin.CorePlugin start

Gruß Tom
 
Diese Frage klingt evtl. Dumm, aber castest du über (Plugin), oder über Plugin.class.cast(Object o)? Wobei die PluginClass natürlich dann vom URLClassLoader geladen ist.
 
@Tom
Deine Mühe in allen Ehren *nein wirklich ... du bist mit einer der besten Java-Profis die ich kenne* ... aber ganz so wollte ichs dann wieder nicht.
Was du nicht beachtest hast : KEIN CLASSPATH
In deinem Beispiel läds du alle Klassen via -cp - Angabe in den ROOT-ClassLoader ... das will ich aber nicht da ich es auch nicht garantieren kann.
Das mit dem ServiceLoader hattest du ja schon damals versucht mir nahe zu bringen *wow ... das du dir echt die Mühe gemacht und diese alten Threads ausgegraben hast* ... aber wie du ja schon selbst gesagt hast ist es auch nicht ganz das was ich will.
Das natürlich dein Beispiel so einwandfrei funktioniert ist klar.
Das stichwort Reflections trifft es noch nicht ganz ... aber es geht in die Richtung.

@Techno
Ja ... ich caste dierekt über Plugin beim Class.newInstance() welches ich auf das Class-Objekt aus dem URLClassLoader anwende.

Ich sehe schon ich muss doch mal schnell ein lauffähiges Beispiel basteln ...
*halbe Stunde später*
Ich habe es mal bewusst einfach gehalten.
Die Ordnerstruktur *root-dir ist hier H:\java\de*:
Code:
H:\java>dir /s de
 Datenträger in Laufwerk H: ist sTiCk
 Volumeseriennummer: A402-F5C4

 Verzeichnis von H:\java\de

28.06.2011  01:41    <DIR>          .
28.06.2011  01:41    <DIR>          ..
28.06.2011  01:41    <DIR>          tutorials
               0 Datei(en),              0 Bytes

 Verzeichnis von H:\java\de\tutorials

28.06.2011  01:41    <DIR>          .
28.06.2011  01:41    <DIR>          ..
28.06.2011  02:13    <DIR>          spikee
               0 Datei(en),              0 Bytes

 Verzeichnis von H:\java\de\tutorials\spikee

28.06.2011  02:13    <DIR>          .
28.06.2011  02:13    <DIR>          ..
28.06.2011  02:11             2.156 Launcher.class
28.06.2011  02:14             2.390 Launcher.jar
28.06.2011  01:51             1.542 Launcher.java
28.06.2011  02:10    <DIR>          lib
28.06.2011  02:11               795 Loader$1.class
28.06.2011  02:11             3.745 Loader.class
28.06.2011  02:14             3.148 Loader.jar
28.06.2011  02:11             2.997 Loader.java
28.06.2011  02:11               697 MainPlugin.class
28.06.2011  02:13             1.103 MainPlugin.jar
28.06.2011  02:10               337 MainPlugin.java
28.06.2011  02:13                32 MainPlugin.rsf
              11 Datei(en),         18.942 Bytes

 Verzeichnis von H:\java\de\tutorials\spikee\lib

28.06.2011  02:10    <DIR>          .
28.06.2011  02:10    <DIR>          ..
28.06.2011  02:10               268 Plugin.class
28.06.2011  01:51               179 Plugin.java
28.06.2011  02:10               272 PluginLoader.class
28.06.2011  02:10               286 PluginLoader.java
               4 Datei(en),          1.005 Bytes

     Anzahl der angezeigten Dateien:
              15 Datei(en),         19.947 Bytes
              11 Verzeichnis(se),  1.475.760.128 Bytes frei

Nun die einzelnen Files

Launcher.java
Java:
package de.tutorials.spikee;
import de.tutorials.spikee.lib.*;
import java.lang.reflect.*;
import java.io.*;
import java.net.*;
public class Launcher
{
	private String PATH=null;
	public static void main(String[] args) throws Exception { (new Launcher()).launch(); } //starten des Launchers
	private Launcher() { setPath(); } //privater Konstruktor um Instanzierung von außen zu verhindern
	private void setPath() //setzt die globale Variable PATH welche den aktuellen Pfad zum Jar-File enthält *funktioniert sowohl IN einem JAR als auch OHNE sowie unter LINUX*
	{
		PATH=this.getClass().getResource(this.getClass().getSimpleName()+".class").toString();
		if(PATH.contains("!"))
			PATH=PATH.substring(0, PATH.indexOf("!"));
		PATH=(new File(PATH.substring(PATH.indexOf("/"), PATH.lastIndexOf("/")))).getAbsolutePath();
	}
	private void launch() throws Exception //eigentlicher launch
	{
		URLClassLoader urlCL=new URLClassLoader(new URL[] { (new File(PATH, "Loader.jar")).toURI().toURL() }); // URLClassLoader auf Loader.jar setzen
		Class<?> Loader=urlCL.loadClass("de.tutorials.spikee.Loader"); // Klasse de.tutorials.spikee.Loader laden
		Object loader=Loader.newInstance(); // Instanz erzeugen
		Method[] methods=Loader.getDeclaredMethods(); // deklarierte Methoden holen
		for(Method method : methods) // foreach
		{
			if(method.getName().equals("load")) // wenn Methoden-Name "load" ist
				method.invoke(loader, (Object[])null); // Methode aufrufen *(Object[])null um Compilerwarnung zu erfüllen
		}
	}
}

Loader.java
Java:
package de.tutorials.spikee;
import de.tutorials.spikee.lib.*;
import java.lang.reflect.*;
import java.io.*;
import java.net.*;
import java.util.*;
import java.util.jar.*;
public class Loader implements PluginLoader
{
	private String PATH=null;
	private Vector<Plugin> plugins;
	public Loader() { setPath(); plugins=new Vector<Plugin>(); }
	private void setPath()
	{
		PATH=this.getClass().getResource(this.getClass().getSimpleName()+".class").toString();
		if(PATH.contains("!"))
			PATH=PATH.substring(0, PATH.indexOf("!"));
		PATH=(new File(PATH.substring(PATH.indexOf("/"), PATH.lastIndexOf("/")))).getAbsolutePath();
	}
	public void load() throws Exception
	{
		File pluginDir=new File(PATH); // aktuelles Verzeichnis als File-Objekt
		File[] pluginJars=pluginDir.listFiles(new FilenameFilter() // alle .jar -Files als Array mit ausnahme Launcher.jar und Loader.jar
		{
			public boolean accept(File path, String name)
			{
				if((name.equals("Launcher.jar"))||(name.equals("Loader.jar"))||(!name.toLowerCase().endsWith(".jar")))
					return false;
				else
					return true;
			}
		});
		for(File pluginJar : pluginJars) // foreach
		{
			String name="FAIL"; // Prüfvariable ob Jar-File auch verwendbares Plugin
			JarFile jarFile=new JarFile(pluginJar); // Plugin als JarFile-Objekt
			Enumeration<JarEntry> entries=jarFile.entries(); // alle Dateien holen
			while(entries.hasMoreElements()) // durch Enumeration gehen
			{
				JarEntry entry=entries.nextElement();
				if(entry.getName().endsWith("Plugin.rsf")) // falls eine Datei mit der Endung "Plugin.rsf" gefunden wird
					name=(new BufferedReader(new InputStreamReader(jarFile.getInputStream(entry)))).readLine(); // Plugin-Name aus dieser Datei lesen
			}
			jarFile.close(); // JarFile closen da sonst nicht über URLClassLoader ladbar
			if(name.equals("FAIL")) // prüfen der Prüfvariable , wenn immer noch "FAIL" dann ist JarFile kein verwendbares Plugin da die RSF-Datei nicht gefunden wurde
				continue;
			URLClassLoader urlCL=new URLClassLoader(new URL[] { pluginJar.toURI().toURL() }); // JarFile in URLClassLoader laden
			Class<?> clazz=urlCL.loadClass(name); // Plugin-Klasse holen
			Plugin plugin=(Plugin)clazz.newInstance(); // Instanz erzeugen
			plugin.loadPlugin(this); // loadPlugin(PluginLoader) - Methode aufrufen
			plugins.add(plugin); // Plugin dem Vector hinzufügen
		}
		for(Plugin plugin : plugins) { plugin.startPlugin(); } // alle Plugins starten
	}
	public Object invoke(String pluginName, String methodName, Object... args) throws Exception // invoker-Methode um von einem Plugin Methoden eines anderen ausführen zu können
	{
		for(Plugin plugin : plugins)
		{
			Class<?> clazz=plugin.getClass();
			if(clazz.getName().equals(pluginName))
			{
					for(Method method : clazz.getDeclaredMethods())
					{
						if(method.getName().equals(methodName))
							return method.invoke(plugin, args);
					}
			}
		}
		return null;
	}
}

lib/Plugin.java
Java:
package de.tutorials.spikee.lib;
public interface Plugin
{
	public void loadPlugin(PluginLoader pluginLoader) throws Exception;
	public void startPlugin() throws Exception;
}

lib/PluginLoader.java
Java:
package de.tutorials.spikee.lib;
public interface PluginLoader
{
	public Object invoke(String pluginName, String methodName, Object... args) throws Exception; // java.lang.reflect.Method.invoke(String, Object...) - work-around um von einem Plugin Methoden eines anderen aufzurufen
}

MainPlugin.java
Java:
package de.tutorials.spikee;
import de.tutorials.spikee.lib.*;
public class MainPlugin implements Plugin
{
	private PluginLoader pluginLoader=null;
	public void loadPlugin(PluginLoader pluginLoader) throws Exception { this.pluginLoader=pluginLoader; }
	public void startPlugin() throws Exception { System.out.println("HELLO"); }
}

MainPlugin.rsf - Diese Datei ist lediglich eine sog. descriptor-Datei um den JAR-Namen frei wählen zu können
Code:
de.tutorials.spikee.MainPlugin

Soo ... nun zum eigentlichen Problem

Packen wir die Jar-Files erstmal wie ich es eigentlich vorhabe :

Launcher.jar
+-> de/tutorials/spikee/Launcher.class

Loader.jar
+-> de/tutorials/spikee/Loader.class
+-> de/tutorials/spikee/Loader$1.class
+-> de/tutorials/spikee/lib/Plugin.class
+-> de/tutorials/spikee/lib/PluginLoader.class

MainPlugin.jar
+-> de/tutorials/spikee/MainPlugin.class
+-> de/tutorials/spikee/MainPlugin.rsf

Und führen das ganze über
Code:
java -jar de\tutorials\spikee\Launcher.jar
aus ... dann erhalten wir das hier
Code:
H:\java>java -jar de\tutorials\spikee\Launcher.jar
Exception in thread "main" java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:601)
        at de.tutorials.spikee.Launcher.launch(Launcher.java:27)
        at de.tutorials.spikee.Launcher.main(Launcher.java:9)
Caused by: java.lang.NoClassDefFoundError: de/tutorials/spikee/lib/Plugin
        at java.lang.ClassLoader.defineClass1(Native Method)
        at java.lang.ClassLoader.defineClass(ClassLoader.java:791)
        at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
        at java.net.URLClassLoader.defineClass(URLClassLoader.java:449)
        at java.net.URLClassLoader.access$100(URLClassLoader.java:71)
        at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
        at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:423)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
        at de.tutorials.spikee.Loader.load(Loader.java:48)
        ... 6 more
Caused by: java.lang.ClassNotFoundException: de.tutorials.spikee.lib.Plugin
        at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
        at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:423)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
        ... 18 more

Um das Beispiel nun ausführen zu können und um an die gewünschte Ausgabe "HELLO" zu kommen muss ich die Jar's jedoch so packen ... *was ich eigentlich nicht will*

Launcher.jar
+-> de/tutorials/spikee/Launcher.class
+-> de/tutorials/spikee/lib/Plugin.class
+-> de/tutorials/spikee/lib/PluginLoader.class

Loader.jar
+-> de/tutorials/spikee/Loader.class
+-> de/tutorials/spikee/Loader$1.class

MainPlugin.jar - nicht verändert.

So ... ich hoffe nach dem ich das hier mal SEHR AUSFÜHRLICH dargestellt habe mal meine eigentliche Frage stellen zu können : warum werden die Interfaces Plugin und PluginLoader nicht über den URLClassLoader mitgeladen und warum hilft auch kein expliziter Aufruf von
Java:
this.getClass().getClassLoader().loadClass("de.tutorials.spikee.lib.Plugin");
innerhalb von Loader.load() ?

Ich möchte hier noch einmal wiederholen das ich NICHT am Classpath rumbasteln möchte um das halbwegs zum laufen zu bekommen.

@Tom
Ich bin aber jetzt im gegensatz zu damals bereit mir das mit dem ServiceLoader mal genauer erklären zu lassen.

Also ... wenn irgendwer eine Idee hat warum das hier nicht so läuft wie es mein Gedanke erdacht hat ... immer her damit xD
 
@Techno
Ich habe mal das mit Class.cast(Object) versucht ... bleibt leider bei exakt der selben Fehlermeldung. Wenn ich versuch ein Class-Object der Klass Plugin zu verwenden bekomme ich einen Compilerfehler das Plugin verlangt wird aber nur Object gefunden wurde ... oder ich hab es nicht ganz verstanden wie ich das machen soll.

Zerbrecht euch mal weiter die Köpfe .. ich muss erstmal los.
 
ich mache hier bewusst einen neuen Post da 1) zeitlicher Unterschied und 2) um im Forum zu zeigen das es was neues gibt

@Tom
Ich habe mir dein Beispiel mit dem ServiceLoader noch mal genau durch gelesen und auch so weit verstanden. Es ist im Prinzip nichts anderes wie meins nur das es mit Java-eigenen Mitteln arbeitet. So weit so gut ... nur der Knackpunkt was in deinem Beispiel damals schon das Problem war wie oben : wie mache ich das ganz so dynamisch OHNE einen CLASSPATH angeben zu müssen ? Wenn ich es mir so einfach machen würde würde ich in das Manifest vom Launcher einfach den Class-Path eintrag auf den Loader setzen und gut wärs ... mit dem Problem das dadurch das Loader.jar gelockt wird und ich es nicht mehr updaten könnte. Und genau da setz ja mein Problem an : wie schaffe ich es das ganze dynamisch zu machen ohne irgendwelche statischen angaben mit CP wo ich angzt haben muss das meine Jar-Files gelockt werden und ich sie so nicht mehr updaten kann ?
 
Hallo,

nur der Knackpunkt was in deinem Beispiel damals schon das Problem war wie oben : wie mache ich das ganz so dynamisch OHNE einen CLASSPATH angeben zu müssen ?
In dem zweiten Link in meinem Post von oben findest du ein Beispiel wie man auch ohne Classpath anpassungen dynamisch zur Laufzeit Plugins oder generell Erweiterung über einen ServiceLoader finden kann:
http://www.tutorials.de/java/358931-services-dynamisch-laden.html#post1859684

da musst du nun keinen erweiterten Classpath für deine Anwendung definieren.

btw. du kannst dem ServiceLoader auch selbst einen Classloader mitgeben, der die URLS zu den (dynamisch zur Laufzeit ermittelten) Plugin-Jars kennt...

wie schaffe ich es das ganze dynamisch zu machen ohne irgendwelche statischen angaben mit CP wo ich angzt haben muss das meine Jar-Files gelockt werden und ich sie so nicht mehr updaten kann ?
Löschen geht nicht... aber AFAIK kann man die jars überschreiben... ansonsten entweder selbst einen CloseableUrlClassLoader implementieren (oder Java 7 verwenden...) der die Jars auch wieder frei gibt. Eine weitere alternative wäre die plugin-jars vor dem laden in einen temporären Folder zu kopieren und diese dann von dort aus über einen URLClassLoader anzusprechen.

Gruß Tom
 
Hey Tom,
das habe ich auch schon ausprobiert. Jedoch schlug auch das wie zu erwarten fehl.
Das Problem welches auch der ServiceLoader hat ist das das Interface scheinbar wie bei meinem Ansatz zum Startzeitpunkt bereits bekannt sein muss. Ein dynamisches nachladen über einen URLClassLoader funktioniert leider genau so wenig wie bei meinem System. Ich erhalte eine Exception das der angegeben Provider nicht gefunden werden kann wenn das Interface in einem Jar liegt welches erst zur Runtime dynamisch geladen wird. Liegt das Interface jedoch schon beim Start vor *entweder im Jar oder über CP eingebunden* läuft es auch.
Nach dem ich nun also eine Menge probiert habe und noch mehr Exceptions bekommen habe habe ich mich schluss endlich dazu endschlossen mein System zu verweden mit der Änderung das ich den PluginHandler nicht in ein extra Jar auslagere sondern dierekt in den Launcher integriere.
Das ganze ist auch kein Problem da wenn sich mal am PluginSystem etwas ändert ich den Launcher sehr leicht updaten kann *Erklärung wie wäre einen neuen Thread wert.*.

Falls also interesse daran besteht wie ich das Problem nun genau gelöst habe einfach posten.
 
Zurück