введение
Если вы знакомы с использованием JDBC для подключения к базе данных, вы должны знать, что в коде должна быть основа для подключения к базе данных.Class.forName("com.mysql.jdbc.Driver");
public static Connection getConnection() throws ClassNotFoundException, SQLException {
if(connection == null){
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/xxx?serverTimezone=UTC", "root", "xxxxxx");
}
return connection;
}
Раньше я не задумывался над тем, зачем нужна такая инструкция, и делаю это прямо по документации, в этой статье я постараюсь объяснить причину этого.
механизм загрузки классов
Перед нашим первым механизмом загрузки классов в Java для следующего.
В Java, если вы хотите использовать класс, вы должны потребовать, чтобы класс был загружен в JVM Процесс загрузки фактически состоит в получении потока двоичных байтов, который определяет класс, через полное имя класса, а затем преобразовать поток байтов в представленную статическую структуру хранения, которая преобразуется в динамическую структуру данных времени выполнения, к которой обращается метод. В то же время объект java.lang.Class создается в памяти как запись доступа к данным (для нашего использования) класса в области методов.
Следующие ситуации вызовут загрузку класса (цитата из >):
- При встрече с четырьмя инструкциями байт-кода new, getstatic, putstatic или invokestatic, если класс не был инициализирован, вам нужно сначала запустить его инициализацию. Наиболее распространенные сценарии кода Java, которые генерируют эти 4 инструкции: при создании экземпляра объекта с использованием нового ключевого слова, чтении или установке статического поля класса (модифицированного с помощью final, статического поля, которое поместило результат в константный пул при компиляции поля time) и при вызове статического метода класса.
- При использовании метода пакета java.lang.reflect для выполнения вызова отражения к классу, если класс не был инициализирован, сначала необходимо запустить его инициализацию.
- При инициализации класса, если обнаруживается, что его родительский класс не был инициализирован, необходимо сначала инициировать инициализацию своего родительского класса.
- Когда виртуальная машина запускается, пользователю необходимо указать основной класс для выполнения (тот, который содержит метод main()), и виртуальная машина сначала инициализирует этот основной класс.
Class.forName
Интерпретация Class.forName в официальной документации Java заключается в том, чтобы динамически загружать класс во время выполнения, а возвращаемым значением является сгенерированный объект класса.
тогда, очевидно, используйте в jdbcClass.forName("com.mysql.jdbc.Driver");
Он просто загружает класс com.mysql.jdbc.Driver в JVM, и большинство людей должны знать об этом.
Но нам нужно знать, что Class.forName, кажется, просто загружает класс, и мы даже ничего не делаем с возвращенным объектом класса, так почему мы можем использовать его непосредственно позже?
Сначала обратите внимание, что Class.forName вызывает собственный метод forName0(...);
@CallerSensitive
public static Class<?> forName(String className)
throws ClassNotFoundException {
Class<?> caller = Reflection.getCallerClass();
return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}
private static native Class<?> forName0(String name, boolean initialize,ClassLoader loader,Class<?> caller);
ForName0 отметить, что есть критический параметрboolean initialize,
; Этот параметр используется для определения того, выполняется ли операция инициализации после загрузки класса. Вы можете видеть, что код верен, это означает, что операция инициализируется.
Процесс инициализации — это фактически процесс присвоения значений переменным (не присвоение начальных значений, и не вызов конструктора). Содержит назначение всех переменных класса и выполнение блока статического кода, включая инициализацию родительского класса.
Посмотрите на класс драйвера com.mysql.jdbc.Driver:
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
public Driver() throws SQLException {
}
static {
try {
DriverManager.registerDriver(new Driver());
} catch (SQLException var1) {
throw new RuntimeException("Can't register driver!");
}
}
}
В этом классе определен блок статического кода, а экземпляр класса драйвера создается в статическом коде и регистрируется в DriverManager, а содержимое блока статического кода будет выполняться в процессе инициализации, поэтому он может передатьDriverManager.getConnection
Получить соединение напрямую.
Другие методы класса загрузки
Нам нужно понять, что загруженные классы в Java видны не только через Class.forName(). Так зачем же выбирать Class.forName() вместо использования других методов загрузки?
ClassLoader.getSystemClassLoader().loadClass()
Вы также можете загрузить класс в JVM через загрузчик классов. пройти черезClassLoader.getSystemClassLoader().loadClass("com.mysql.jdbc.Driver");
Также можно загрузить классы драйверов.
Но если мы подробнее рассмотрим реализацию loadClass:
public Class<?> loadClass(String name) throws ClassNotFoundException {
return loadClass(name, false);
}
protected Class<?> loadClass(String name, boolean resolve);
Вы можете видеть, что он вызывает перегруженный метод, который также имеет переменную типа boolean.boolean resolve
, который по умолчанию принимает значение false при вызове. Этот параметр используется для определения необходимости связывания загруженного класса.Если операция связывания не выполняется, операции инициализации не будет.
Поэтому, если используется этот способ загрузки классов, теоретически класс драйвера не используется.
новое ключевое слово
Вы также можете использовать новое ключевое слово для операций загрузки.При использовании нового ключевого слова будет проверяться, был ли загружен класс.Если он не был загружен, будет выполнена операция загрузки. Поэтому мы также можем написать это в нашем классе:
public static Connection getConnection() throws ClassNotFoundException, SQLException {
if(connection == null){
new Driver();//会自动调用静态代码块
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/xxx?serverTimezone=UTC", "root", "xxxx");
}
return connection;
}
А на самом деле, потому что в статическом коде класса драйвера на самом деле есть операция инстанцирования объекта и его регистрации в DriverMananger. Таким образом, процесс создания экземпляра объекта вообще отсутствует. Просто используйте Class.forName, который также является процессом оптимизации.
Class.forName("com.mysql.jdbc.Driver") не может использоваться
В ходе тестирования было установлено, что даже если он не показывает использованиеClass.forName("com.mysql.jdbc.Driver")
Я также могу подключиться к базе данных, что на какое-то время странно.
Покопавшись в коде отслеживания, я обнаружил, что пока мы ввели пакет драйвера mysql, класс будет создан по умолчанию в соответствии с файлом конфигурации, предоставленным в пакете драйвера.
Так что на самом деле, пока вводится пакет драйверов, подключение можно получить напрямую через DriverManage с помощью jdbc. (собственно механизм spi)
public static Connection getConnection() SQLException {
return DriverManager.getConnection("jdbc:mysql://localhost:3306/xxx?serverTimezone=UTC", "root", "xxxxxx");
}