410013796724260
• Webmoney
R335386147728
Z369087728698
Динамическая загрузка JDBC-драйвераС чем может быть связана необходимость динамической загрузки JDBC-драйвера? Причины могут быть разные. Я лучше опишу связанную с темой статьи задачу, которую пришлось решать. Кстати, после разрешения проблемы пришлось подумать над вопросом, как представить и в каком разделе сайта разместить данные наработки? Но об этом позже, а сейчас переходим к «телу» ...
Представьте, что Вы разрабатываете сложное приложение в OSGi-технологии. Структура приложения,
включающая базу данных, создана и всё работает нормально; проблем с фукнционированием системы не наблюдается. Но
наступает момент, когда Вы переходите к комплексному тестированию системы. Вы знаете, что отдельные транзакции,
связанные с добавлением, обновлением и удалением записи в одной таблице затрагивают сразу несколько записей в других
таблицах. Ошибка в алгоритме может полностью нарушить связанные значения в нескольких таблицах. Лечение, конечно же,
можно найти, но насколько вовремя будет поставлен диагноз. А если после каждого «приема пищи» сразу же «принимать
лекарство», то затягивается время транзакции. Да и зачем такая «пища», если её принимать вместе с «лекарством». Не лучше
ли сразу создать нормальный алгоритм. То есть, необходима детальная отладка алгоритма (бизнес-логики) на большом
количестве записей. В этом случае не обойтись без JUnit.
Конечно же, динамическая загрузка jar-библиотек в режиме run-time возможна в различных ситуациях, и не только при отладке приложения/модуля с использованием JUnit. Поэтому данная статья может быть полезна и Вам. А я выкладываю её на сайте, чтобы в будущем меньше «напрягаться» при возникновении подобных проблем. Как говорится, подальше положешь – поближе возьмешь. Класс загрузки JDBC-драйвераВ качестве сервера базы данных выбран Apache Derby, который будет стартован из JVM вместе с test-case, т.е. в режиме EmbeddedDriver. Вы можете, при необходимости, выбрать другой JDBC-дрйвер, подключаясь к другому типу СУБД. Для подключения к СУБД нам потребуется :
Ниже представлен листинг класса JDBCConnection для динамической загрузки JDBC-драйвера. Здесь все тривиально просто. Главная задача – определить значение переменной connection, имеющей тип java.sql.Connection. Наименование драйвера определенно текстовой константой DRV. Остальные текстовые константы будут использованы при подключении к серверу БД. В конструкторе вызывается метод загрузки драйвера loadDriverJDBC, исходный текст которого представлен ниже, чтобы не загромождать листинг класса. Открытый метод getConnection() возвращает объект подключения к серверу БД java.sql.Connection.
import java.io.File;
import java.io.IOException;
import java.util.Properties;
import java.net.URL;
import java.net.URLClassLoader;
import java.sql.Driver;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.DriverManager;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
public class JDBCConnection
{
Connection connection = null;
final String DRV="org.apache.derby.jdbc.EmbeddedDriver";
final String ENCODING = "characterEncoding";
final String UTF8 = "UTF-8";
final String STR_REGISTER = "Register JDBC driver :"
+ "\n\t" + DRV;
//-----------------------------------------------------
public JDBCConnection()
{
loadDriverJDBC();
}
//-----------------------------------------------------
public Connection getConnection()
{
return connection;
}
//-----------------------------------------------------
private void loadDriverJDBC()
{
// исходный код представлен ниже
}
}
Метод загрузки JDBC-драйвераНиже представлен листинг метода loadDriverJDBC динамической загрузки JDBC-драйвера сервера Apache Derby. Сначала определим значения текстовых констант PATH_driver и URL_db. После этого необходимо подготовить загрузчик драйвера URLClassLoader. В качестве загрузчика loader используем ClassLoader текущего класса. Можно также использовать и системный загрузчик (закомментированные строки). После определения всех необходимых параметров для загрузчика переходим к рефлексии для определения метода (java.lang.reflect.Method), который будет выполнять загрузку. Здесь самое главное понять, что мы должны работать в одном «информационном пространстве» JVM, чтобы иметь доступ к пакетам и классам. После загрузки JDBC-драйвера необходимо выполнить его регистрацию, после чего можно подключаться к серверу БД.
private void loadDriverJDBC()
{
final String PATH_driver; // путь к драйверу
final String URL_db ; // URL JDBC-подключения
PATH_driver="D:/libs/org.apache.derby-10.10.1000001.jar";
URL_db="jdbc:derby:D:/data/db;user=derby;password=derby";
URL[] urls ;
URL jarFile;
URLClassLoader loader ;
Method method ;
try {
File driverJar = new File(PATH_driver);
Class<?> cls = this.getClass();
String file = "file:" +
driverJar.getAbsolutePath()+"!/";
urls = new URL[] {driverJar.toURI().toURL()};
jarFile = new URL("jar", "127.0.0.1", file);
loader = new URLClassLoader(urls,
cls.getClassLoader());
// loader = new URLClassLoader(urls,
// System.class.getClassLoader());
cls = URLClassLoader.class;
try {
//--- Загрузка драйвера (jar-файла) ---
Class<?>[] clss = new Class[] {URL.class};
Object[] objects = new Object[] {jarFile};
method = cls.getDeclaredMethod("addURL", clss);
method.setAccessible(true);
method.invoke(loader, objects);
//--- Регистрация JDBC-драйвера ---
cls = Class.forName(DRV, true, loader);
Driver driver;
driver = (Driver) cls.newInstance();
DriverManager.registerDriver(driver);
System.out.println(STR_REGISTER);
//--- Подключение к серверу БД ---
Properties props;
props = new Properties();
props.setProperty(ENCODING, UTF8);
connection = driver.connect(URL_db, props);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
}
Тестирование класса загрузки JDBC-драйвераВ заключение листинг простенького класса тестирование нашего загрузчика JDBC-драйвера. Принимая во внимание, что объект подключения connection может быть использован в нескольких test-case'х, то его инициализация выполняется в методе init с дескриптором @BeforeClass, т.е. один раз при старте класса. Отключение от сервера БД выполняется в методе closeConnection с дескриптором @AfterClass, т.е. один раз после завершения всех тестов.
import org.junit.Test;
import org.junit.Assert;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import java.sql.Connection;
import java.sql.SQLException;
public class TestConnection extends Assert
{
static Connection connection = null;
//-----------------------------------------------------
@BeforeClass
public static void init()
{
JDBCConnection jdbc = new JDBCConnection();
connection = jdbc.getConnection();
}
//-----------------------------------------------------
@Test
public void test01_openConnection()
{
assertTrue(connection != null);
}
//-----------------------------------------------------
@AfterClass
public static void closeConnection()
{
try {
if (connection != null)
connection.close();
} catch (SQLException e) {}
}
//-----------------------------------------------------
}
Связанные темыВозвращаясь к поставленному в начале статьи вопросу, в каком разделе разместить данную страницу, перечислю только темы, затронутые в данном примере :
В любом разделе в качестве практического примера можно было бы разместить данную статью. Но поскольку основная задача была связана с JDBC, то она и попала в данный раздел. |
