2008-11-14 1 views
17

Ich muss eine JDBC-Verbindung zu einer Datenbank testen. Der Java-Code zu tun, sollte so einfach sein wie:Wie verwende ich einen JDBC-Treiber von einem beliebigen Ort aus

DriverManager.getConnection("jdbc connection URL", "username", "password"); 

Die Treiber-Manager der entsprechenden den Treiber für die gegebene Verbindung URL Lookup werden. Allerdings muss ich in der Lage sein, den JDBC-Treiber (jar) zur Laufzeit zu laden. Ie. Ich habe nicht den JDBC-Treiber auf dem Klassenpfad der Java-Anwendung, die das Code-Schnipsel oben ausführt.

So kann ich den Treiber laden diesen Code verwenden, zum Beispiel:

URLClassLoader classLoader = new URLClassLoader(new URL[]{"jar URL"}, this.getClass().getClassLoader()); 
Driver driver = (Driver) Class.forName("jdbc driver class name", true, classLoader).newInstance(); 

Aber dann der Treiber-Manager wird es immer noch nicht abholen, wie ich es nicht sagen kann, welche Klassenlader zu verwenden. Ich habe versucht, den Kontext-Classloader des aktuellen Threads zu setzen und es funktioniert immer noch nicht.

Hat jemand eine Idee über den besten Weg, das zu erreichen?

+0

Gibt es einen guten Grund, warum Sie den Treiber nicht auf dem Klassenpfad haben? –

+0

Ja. Die Anwendung kann eine Verbindung zu vielen Datenbanken herstellen. Außerdem kann ich aus Lizenzgründen nicht alle Treiber bündeln. Was ich erreichen möchte, ist ein einfacher Dialog für den Benutzer, um das Glas zu laden, während die Anwendung läuft. – SaM

+0

Dort dachte ich wieder wie ein serverseitiger Entwickler ... :) –

Antwort

17

Aus dem Artikel Pick your JDBC driver at runtime; Ich werde den Code hier nur als Referenz veröffentlichen.

Die Idee besteht darin, den Treibermanager zu glauben, dass der Treiber vom Systemklassenlader geladen wurde. Um dies zu tun verwenden wir diese Klasse:

public class DelegatingDriver implements Driver 
{ 
    private final Driver driver; 

    public DelegatingDriver(Driver driver) 
    { 
     if (driver == null) 
     { 
      throw new IllegalArgumentException("Driver must not be null."); 
     } 
     this.driver = driver; 
    } 

    public Connection connect(String url, Properties info) throws SQLException 
    { 
     return driver.connect(url, info); 
    } 

    public boolean acceptsURL(String url) throws SQLException 
    { 
     return driver.acceptsURL(url); 
    } 

    public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException 
    { 
     return driver.getPropertyInfo(url, info); 
    } 

    public int getMajorVersion() 
    { 
     return driver.getMajorVersion(); 
    } 

    public int getMinorVersion() 
    { 
     return driver.getMinorVersion(); 
    } 

    public boolean jdbcCompliant() 
    { 
     return driver.jdbcCompliant(); 
    } 
} 

diese Weise kann der Fahrer Sie DelegatingDriver ist vom Typ registrieren, die mit dem System Classloader geladen wird. Sie müssen jetzt nur noch den Treiber laden, den Sie wirklich verwenden wollen, mit dem von Ihnen gewünschten Classloader. Zum Beispiel:

URLClassLoader classLoader = new URLClassLoader(new URL[]{"path to my jdbc driver jar"}, this.getClass().getClassLoader()); 
Driver driver = (Driver) Class.forName("org.postgresql.Driver", true, classLoader).newInstance(); 
DriverManager.registerDriver(new DelegatingDriver(driver)); // register using the Delegating Driver 

DriverManager.getDriver("jdbc:postgresql://host/db"); // checks that the driver is found 
5

Das Problem ist DriverManager führt "Aufgaben der unmittelbaren Anrufers Class Loader-Instanz mit". Siehe Richtlinie 6-3 von Secure Coding Guidelines for the Java Programming Language, version 2.0. Der Systemklassenlader ist in diesem Fall in keiner Weise besonders.

Nur für Kicks, schrieb ich eine blog entry zu diesem Thema eine Weile zurück. Meine Lösung, obwohl komplizierter als Nick Sayer's solution, ist vollständiger und funktioniert sogar von nicht vertrauenswürdigem Code. Beachten Sie auch URLClassLoader.newInstance gegenüber new URLClassLoader.

Verwandte Themen