Это нарушает модель родительского делегирования.
Модель делегирования требует, чтобы любой запрос загрузчика классов на загрузку данного класса был сначала делегирован загрузчику родительского класса, прежде чем запрашиваемый загрузчик класса попытается загрузить сам класс.
Таким образом, в соответствии с моделью делегирования java.sql.Connection в вашем фрагменте кода предполагается передать в загрузчик классов BootStrap (корневой загрузчик классов) с помощью System Classloader (он же загрузчик классов приложений), а загрузчик классов BootStrap попытается загрузить Это. И это можно загрузить.
попробовать:
public static void main(String[] args){
System.out.println(Connection.class.getClassLoader());
}
Вывод равен нулю, что означает, что он загружен корневым загрузчиком классов.
Но если вы сделаете это
public static void main(String[] args){
Connection connection = null;
try {
connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/foo", "username", "password");
} catch (SQLException e) {
e.printStackTrace();
}
System.out.println(connection.getClass().getClassLoader());
}
Вывод: sun.misc.Launcher$AppClassLoader@18b4aac2 или что-то в этом роде, означающее, что он загружен Системным загрузчиком классов (Application Classloader).
Итак, мы продемонстрировали, что корневой загрузчик классов может загружать java.sql.Connection, но вместо этого загружается его дочерним классом, системным загрузчиком классов. И это является нарушением модели делегирования в соответствии с ее определением.
Тогда встает вопрос Как и Почему ?
Что касается How, уловка находится внутри класса DriverManager.
от Javadoc
private static Connection getConnection(
String url, java.util.Properties info, Class<?> caller) throws SQLException {
// ...
ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;
callerCL = Thread.currentThread().getContextClassLoader();
// ...
for(DriverInfo aDriver : registeredDrivers) {
if(isDriverAllowed(aDriver.driver, callerCL)) {
try {
// ...
Connection con = aDriver.driver.connect(url, info);
// ...
return con;
}
Он пытается получить загрузчик классов из текущего потока, который обычно является системным загрузчиком классов. И использовать его для загрузки реализации драйвера базы данных и возврата объекта соединения.
Или, проще говоря, родительский загрузчик классов пытается использовать дочерний загрузчик классов для загрузки некоторых классов! Согласно родительскому делегированию, родительский загрузчик классов даже не должен знать о существовании дочернего загрузчика классов.
Тогда встает вопрос: почему Sun / Oracle делает это?
Классы, загруженные двумя разными загрузчиками классов, не могут иметь доступ друг к другу. Таким образом, класс java.sql.Connection и его реализация должны быть загружены одним и тем же загрузчиком классов для работы.
Тогда мы можем либо
1) Загрузите как java.sql.Connection, так и его классы реализации, предлагаемые конкретными поставщиками баз данных загрузчиком классов Bootstrap.
или же
2) Загрузите оба из них загрузчиком системных классов.
Первый вариант здесь невозможен, так как мы знаем, что загрузчик классов Bootstrap загружает классы из rt.jar. Он не загружает классы из вашего пути к классам.
Второй вариант - против модели родительского делегирования, поэтому модель здесь нарушена. Это нарушение остается спорным, и некоторые люди считают это плохой дизайн.