Как использовать драйвер JDBC из произвольного местоположения - PullRequest
17 голосов
/ 14 ноября 2008

Мне нужно проверить соединение JDBC с базой данных. Код Java для этого должен быть таким простым:

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

Диспетчер драйверов найдет соответствующий драйвер для данного URL-адреса подключения. Однако мне нужно иметь возможность загрузить драйвер JDBC (jar) во время выполнения. Т.е. у меня нет драйвера JDBC на пути к классам Java-приложения, которое выполняет фрагмент кода выше.

Таким образом, я могу загрузить драйвер, используя этот код, например:

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

Но тогда диспетчер драйверов все равно не поднимет его, поскольку я не могу сказать, какой загрузчик классов использовать. Я попытался установить контекстный загрузчик классов текущего потока, и он все еще не работает.

Кто-нибудь знает, как лучше всего этого добиться?

Ответы [ 2 ]

18 голосов
/ 14 ноября 2008

Из статьи Выберите драйвер JDBC во время выполнения ; Я просто собираюсь опубликовать код здесь для справки.

Идея состоит в том, чтобы обмануть диспетчер драйверов, заставляя их думать, что драйвер был загружен из системного загрузчика классов. Для этого мы используем этот класс:

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();
    }
}

Таким образом, регистрируемый вами драйвер имеет тип DelegatingDriver, который загружается с системным загрузчиком классов. Теперь вам просто нужно загрузить драйвер, который вы действительно хотите использовать, используя любой загрузчик классов, который вы хотите. Например:

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 голосов
/ 14 ноября 2008

Проблема в том, что DriverManager выполняет "задачи, используя экземпляр загрузчика классов непосредственного абонента". См. Руководство 6-3 Правила безопасного кодирования для Язык программирования Java, версия 2.0 . Загрузчик системных классов в этом случае не является чем-то особенным.

Просто ради пинка я недавно написал в блоге на эту тему. Мое решение, хотя и более сложное, чем решение Ника Сейера , является более полным и даже работает из ненадежного кода. Также обратите внимание, что URLClassLoader.newInstance предпочтительнее, чем new URLClassLoader.

...