libreria - mysql java
Cómo usar un controlador JDBC desde una ubicación arbitraria (2)
Necesito probar una conexión JDBC a una base de datos. El código de Java para hacer eso debe ser tan simple como:
DriverManager.getConnection("jdbc connection URL", "username", "password");
El administrador del controlador buscará el controlador apropiado para la URL de conexión dada. Sin embargo, necesito poder cargar el controlador JDBC (jar) en tiempo de ejecución. Es decir, no tengo el controlador JDBC en el classpath de la aplicación java que ejecuta el fragmento de código anterior.
Así que puedo cargar el controlador usando este código, por ejemplo:
URLClassLoader classLoader = new URLClassLoader(new URL[]{"jar URL"}, this.getClass().getClassLoader());
Driver driver = (Driver) Class.forName("jdbc driver class name", true, classLoader).newInstance();
Pero entonces el administrador del controlador aún no lo recogerá, ya que no puedo decirle qué cargador de clases usar. Intenté configurar el cargador de clases de contexto del subproceso actual y todavía no funciona.
¿Alguien tiene alguna idea sobre la mejor manera de lograr eso?
El problema es que DriverManager
realiza "tareas usando la instancia del cargador de clases del llamante inmediato". Consulte la Pauta 6-3 de las Pautas de codificación segura para Java Programming Language, versión 2.0 . El cargador de clases del sistema no es de ninguna manera especial en este caso.
Solo por diversión, escribí una entrada en el blog sobre este tema hace un tiempo. Mi solución, aunque más complicada que la solución de Nick Sayer , es más completa e incluso funciona a partir de un código que no es de confianza. También tenga en cuenta que URLClassLoader.newInstance
es preferible a new URLClassLoader
.
Del artículo Elija su controlador JDBC en tiempo de ejecución ; Voy a publicar el código aquí como referencia.
La idea es engañar al administrador del controlador para que piense que el controlador se cargó desde el cargador de clases del sistema. Para hacer esto usamos esta clase:
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();
}
}
De esta forma, el controlador que registra es del tipo DelegatingDriver
que está cargado con el cargador de clases del sistema. Ahora solo tiene que cargar el controlador que realmente desea usar utilizando el cargador de clases que desee. Por ejemplo:
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