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, то она и попала в данный раздел. |