2010-11-17 2 views
35

Я только что узнал о java.sql package. Он использует Class.forName() для динамической загрузки драйвера, который расширяет DriverManager. Затем мы получаем соединение с использованием метода DriverManager.getConnection().Как работает Class.forName()?

Так как же все работает?
Как класс DriverManager знает, как получить соединение, не используя имя класса для фактического драйвера.

Также мы можем использовать Class.forName() для пользовательских приложений ... если это объясняется примером, я буду очень рад.

+0

Также см http://stackoverflow.com/a/8053125/632951 – Pacerier

ответ

51

Class.forName просто загружает класс, в том числе работает его статические инициализаторы, как это:

class Foo { 
    static { 
     System.out.println("Foo initializing"); 
    } 
} 

public class Test { 
    public static void main(String [] args) throws Exception { 
     Class.forName("Foo"); 
    } 
} 

Все остальные процедуры вы говорите это JDBC-специфичны. Водитель, который реализует Driver, не распространяется на DriverManager - просто регистрирует соответствующий экземпляр с использованием DriverManager.registerDriver. Затем, когда DriverManager необходимо найти драйвер для конкретной строки подключения, он вызывает acceptsURL по каждому зарегистрированному драйверу по очереди, пока не будет сказано: «Да, я могу быть драйвером для этого соединения».

Обратите внимание, что этот способ регистрации драйверов является достаточно старомодным - посмотрите на документы для DriverManager для более современных способов доступа к источнику данных.

+0

мой запрос разрешения от 1-ой линии для вас ответ сэр. – Simmant

+2

@Jon Хороший пример, но где класс 'com.mysql.jdbc.Driver' для класса Class.forName (" com.mysql.jdbc.Driver ");' как я пытался импортировать com.mysql.jdbc.Driver 'все еще не работает – UnKnown

+2

@UnKnown: Он находится в файле jar MySQL. Но вам не нужно импортировать его - вы обычно позволяете JDBC инициализировать его напрямую, и вы ссылаетесь только на классы JDBC в своем коде. –

12

Class.forName(..) загружает и инициализирует целевой класс. . Это, в свою очередь, означает, что статические инициализатор блоки вызываются (код определяется в static { .. }

Если посмотреть, например, драйвер в MySQL, в этом статическом блоке драйвер регистрирует себя: DriverManager.registerDriver(new Driver());

можно опустить Class.forName(..) и зарегистрировать драйвер самостоятельно, если вы можете «позволить себе» во время компиляции зависимости от водителя в MySQL.

Тем не менее, он редко будет уместным использовать Class.forName(..) для инициализации классов из вашего приложения, потому что во время компиляции зависимость является не проблема.

Также обратите внимание, что Class.forName(..)is no longer required для JDBC с версии 4. Используя механизм service provider, вы можете проинструктировать диспетчера драйверов, что загрузить с системным свойством.

3

Причина Class.forName() часто упоминается в примерах SQL, потому, что не было никакой магии сказать JDBC DriverManager как для отображения URL JDBC, предоставляемой реальным драйвером.

E.g. «mysql» должен сопоставляться заданному классу MySQL, «тонким» картам класса Oracle, «as400» относится к классу DB2/400.

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

В настоящее время присутствуют волшебные крючки, позволяющие JVM автоматически обнаруживать драйверы (если они достаточно новые), поэтому вызов лишний, но по привычке многие по-прежнему используют его.

4

Когда мы создаем instace класса с помощью нового оператора, он делает две вещи

  1. загрузить класс в памяти, если он не загружен - , что означает создание в памяти представление класса из файла .class, чтобы экземпляр мог быть создан из него. Это включает инициализацию статических переменных (разрешение этого класса)
  2. создать экземпляр этого класса и сохранить ссылку на переменную.

Class.forName делает только первое место. Он загружает класс в память и возвращает эту ссылку как экземпляр класса. Если мы хотим создать экземпляр, тогда мы можем вызвать метод newInstance этого класса. который будет вызывать конструктор по умолчанию (без конструктора аргументов). Обратите внимание, что если конструктор по умолчанию недоступен, то метод newInstance будет вызывать IllegalAccessException. и если класс является абстрактным классом или интерфейсом или у него нет конструктора по умолчанию, тогда он будет вызывать InstantiationException. Если какое-либо исключение возбуждается при разрешении этого класса, оно выдает ExceptionInInitializerError.

Если конструктор по умолчанию не определен, мы должны вызвать конструктор defiend с использованием API отражения.

Но главное преимущество с Class.forName заключается в том, что оно может принимать имя класса как аргумент String. Таким образом, мы можем передавать имя класса динамически. Но если мы создадим экземпляр класса с использованием нового оператора, имя класса не может быть изменено динамически.

Class.forName() inturn вызовет метод loadClass вызывающего класса ClassLoader (классLode класса, из которого вызывается Class.forName).

По умолчанию Class.forName() разрешает этот класс. что означает, инициализировать все статические переменные внутри этого класса. то же самое может быть изменено с помощью перегруженного метода Class.forName(String name,boolean initialize,ClassLoader loader)

Основной причиной для водителя загрузки с использованием JDBC Class.forName() это, водитель может динамически изменяться. в статическом блоке все Драйверы создадут экземпляр самого себя и зарегистрируют этот класс с помощью DriverManager с использованием метода DriverManager.registerDriver(). Поскольку по умолчанию разрешает класс, он инициализирует статический инициализатор. Так что, когда мы называем Class.forName("com.sun.jdbc.odbc.JdbcOdbcDriver"), класса Driver будет загружен, инстанциированы и регистры с DriverManager

Так что, если вы используете новый оператор вы должны сделать следующие вещи.
Код:

Driver drv = new com.sun.jdbc.odbc.JdbcOdbcDriver(); 
DriverManager.registerDriver(drv);