Du verwendest einen veralteten Browser. Es ist möglich, dass diese oder andere Websites nicht korrekt angezeigt werden. Du solltest ein Upgrade durchführen oder ein alternativer Browser verwenden.
Hallo Gemeinde,
ist es möglich in einem laufenden Javaprogramm den CLASSPATH zu ändern, so das der geänderte CLASSPATH auch für das laufende Programm genutzt wird? Und falls ja wie?
Hintergrund ist, das ich ein Javaprogramm mit Zugriff auf eine MySQL Datenbank schreiben möchte. Allerdings erfahre ich erst zur Laufzeit, wo sich der JDBC Treiber befindet. Dummerweise weiss ich es beim Start des Programms noch nicht.
Viele liebe Grüße Christian
Den Classpath direkt kannst du nicht ändern, und falls es doch über irgendwelche Tricks geht würde ich es nicht machen. Sinnvoller dürfte es ein den URLClassLoader zu verwenden um das Jar des Treibers zu laden und dann gezielt selbst den Treiber zu instanziieren, anstatt über den DriverManager.
@Empire@Work
Wenn man z.B. einen Datenbank-Manager schreibt der mit mehreren Datenbanken arbeiten können soll, man aber erst nach Start der App den Driver auswählen kann.
@TO
JA, man kann den System-ClassLoader "hacken" da dieser auch nur eine Instanz von URLClassLoader ist und man so mit Reflections addURL() callen kann. Was aber zur Problemlösung nicht viel beitragen wird.
Da du schreibst du möchtest zur Runtime einen JDBC-Driver laden sag ichs dir leiber gleich : mit URLClassLoader wirst du nicht sehr weit kommen.
Grund : JDBC-Driver verwenden die ServiceLoader-API um beim Start der VM bereits geladen zu sein. Darum muss man auch dieses [c]Class.forName()[/c] nur bei denen machen die die ServiceLoader-API nicht nutzen, und das sind mitlerweile nur noch sehr wenige.
Was aber eher das Problem ist das wenn du z.B. den MySQL/J-Connector über einen URLClassLoader lädst dieser spätestens beim DriverManger.getConnection() eine Exception schmeißen wird. Warum das so ist kann ich dir auch nicht genau sagen, aber ich weis das gerade bei MySQL/J die Bedingung ist das dieser bereits zum Start der VM verfügbar sein muss.
Um dem zu entgehen kannst du nur mit einem "Dummy" tricksen. Dieser "Dummy" sieht dabei so aus (Java7 Version) :
Java:
import java.sql.*;
import java.util.*;
import java.util.logging.*;
public class DummyDriver implements Driver
{
private Driver driver;
private DummyDriver() { }
public DummyDriver(Driver driver)
{
this.driver=driver;
}
public boolean acceptsURL(String url) throws SQLException { return driver.acceptsURL(url); }
public Connection connect(String url, Properties info) throws SQLException { return driver.connect(url, info); }
public int getMajorVersion() { return driver.getMajorVersion(); }
public int getMinorVersion() { return driver.getMinorVersion(); }
public Logger getParentLogger() throws SQLFeatureNotSupportedException { return driver.getParentLogger(); }
public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException { return driver.getPropertyInfo(url, info); }
public boolean jdbcCompliant() { return driver.jdbcCompliant(); }
}
Für Java6 lässt du einfach "getParentLogger" weg.
Dadurch das DummyDriver bereits während des StartUp im ClassPath liegt hat die VM nun keine Probleme mehr damit über diese Klasse gekapselte Driver zu verwenden. Um nun aber deinen Driver beim DriverManager anzumelden kannst du dann diesen Code nutzen (mal als URLClassLoader-Variante) :
Java:
URLClassLoader cl=new URLClassLoader(new URL[] { new URL("/*absoluter Pfad zum Driver.jar*/") });
Driver driver=(Driver)cl.loadClass("/*voller Klassenname mit Package*/").newInstance();
DriverManager.registerDriver(new DummyDriver(driver));
Vorraussetzung für diese Methode ist natürlich das du den vollen Klassennamen des JDBC-Drivers kennst (also das was du sonst Class.forName()) übergeben würdest. Da wie oben gesagt mitlerweile fast alle die ServiceLoader-API verwenden kann man mit ZipFile/JarFile nach "/services/java.sql.Driver" suchen und den Inhalt lesen. Diesen setzt man dann bei loadClass() ein.
Ich weis das das ganze wie ein "Hack" aussieht, aber leider ist es nur so möglich (auch in Java7) einen JDBC-Driver zur Runtime zu laden. Wenn man es ohne diesen Dummy versucht wirft einem der Driver ne ganze Tonne an Exceptions (warum auch immer).
Der Grund warum ich das so genau weis ist weil ich mal das gleich Probleme hatte. Und das war die einzige Lösung.