Я разрабатываю плагин Eclipse, который подходит для модели клиент-сервер. Это коммерческий проект, поэтому мы не можем распространять драйверы JDBC для различных баз данных, которые мы поддерживаем с помощью плагина.
Итак, я разработал страницу настроек, чтобы позволить пользователю находить jar-файлы и иметь простой механизм обнаружения, который перебирает классы в jar-файлах, загружая каждый из них, чтобы убедиться, что он реализует интерфейс java.sql.Driver. Все это прекрасно работает.
Но суть в том, что я использую Hibernate. А Hibernate использует Class.forName () для создания экземпляра драйвера JDBC.
Если я пытаюсь использовать следующее, я получаю ClassNotFoundException
.
public Object execute(final IRepositoryCallback callback)
{
final DatabaseDriverClassLoader loader = new DatabaseDriverClassLoader(
Activator.getDefault().getDatabaseDriverRegistry());
final ClassLoader oldLoader = Thread.currentThread()
.getContextClassLoader();
try
{
Thread.currentThread().setContextClassLoader(loader);
try
{
final SessionFactory sessionFactory = this.configuration
.buildSessionFactory();
if (sessionFactory != null)
{
final Session session = sessionFactory
.openSession();
if (session != null)
{
// CHECKSTYLE:OFF
try
// CHECKSTYLE:ON
{
return callback.doExecute(session);
}
finally
{
session.close();
}
}
}
connection.close();
}
finally
{
}
}
// CHECKSTYLE:OFF
catch (Exception e)
// CHECKSTYLE:ON
{
RepositoryTemplate.LOG.error(e.getMessage(), e);
}
finally
{
Thread.currentThread().setContextClassLoader(oldLoader);
}
return null;
}
И если я сам пытаюсь создать драйвер следующим образом, я получаю исключение SecurityException.
public Object execute(final IRepositoryCallback callback)
{
final DatabaseDriverClassLoader loader = new DatabaseDriverClassLoader(
Activator.getDefault().getDatabaseDriverRegistry());
final ClassLoader oldLoader = Thread.currentThread()
.getContextClassLoader();
try
{
Thread.currentThread().setContextClassLoader(loader);
final Class driverClass = loader.loadClass(this.connectionDriverClassName);
final Driver driver = (Driver)driverClass.newInstance();
DriverManager.registerDriver(driver);
try
{
final Connection connection = DriverManager.getConnection(
this.connectionUrl, this.connectionUsername,
this.connectionPassword);
final SessionFactory sessionFactory = this.configuration
.buildSessionFactory();
if (sessionFactory != null)
{
final Session session = sessionFactory
.openSession(connection);
if (session != null)
{
// CHECKSTYLE:OFF
try
// CHECKSTYLE:ON
{
return callback.doExecute(session);
}
finally
{
session.close();
}
}
}
connection.close();
}
finally
{
DriverManager.deregisterDriver(driver);
}
}
// CHECKSTYLE:OFF
catch (Exception e)
// CHECKSTYLE:ON
{
RepositoryTemplate.LOG.error(e.getMessage(), e);
}
finally
{
Thread.currentThread().setContextClassLoader(oldLoader);
}
return null;
}
РЕДАКТИРОВАТЬ: я не уверен, что это лучший вариант, но я выбрал подход к реализации собственного ConnectionProvider
, который позволил мне создать экземпляр драйвера, используя Class.forName()
, и затем я открываю соединение, используя Driver.connect()
вместо DriverManager.getConnection()
. Это довольно простой, но мне не нужен пул соединений в моем конкретном случае использования.
Метод configure()
был следующим:
public void configure(final Properties props)
{
this.url = props.getProperty(Environment.URL);
this.connectionProperties = ConnectionProviderFactory
.getConnectionProperties(props);
final DatabaseDriverClassLoader classLoader = new DatabaseDriverClassLoader(
Activator.getDefault().getDatabaseDriverRegistry());
final String driverClassName = props.getProperty(Environment.DRIVER);
try
{
final Class driverClass = Class.forName(driverClassName, true,
classLoader);
this.driver = (Driver)driverClass.newInstance();
}
catch (ClassNotFoundException e)
{
throw new HibernateException(e);
}
catch (IllegalAccessException e)
{
throw new HibernateException(e);
}
catch (InstantiationException e)
{
throw new HibernateException(e);
}
}
И метод getConnection()
выглядит следующим образом:
public Connection getConnection()
throws SQLException
{
return this.driver.connect(this.url, this.connectionProperties);
}